下面由workerman教學(xué)專欄跟大家介紹workerman原始碼分析之啟動(dòng)過程,希望對(duì)需要的朋友有幫助!
#workerman
版本:3.1.8(linux)
模型:GatewayWorker(Worker模型可與之類比)
註:只貼出講解部分程式碼,出處以檔名形式給出,大家可自行查看
workerman最初只開發(fā)了Linux版本,win是後來(lái)增加的,基於命令列模式運(yùn)行(cli)。
多進(jìn)程模型
工作進(jìn)程,Master、Gateway和Worker,Gateway主要用於處理IO事件,保存客戶端連結(jié)狀態(tài),將資料處理請(qǐng)求發(fā)送給Worker等工作,Worker則是完全的業(yè)務(wù)邏輯處理,前者為IO密集型,後者為計(jì)算密集型,它們之間通過網(wǎng)絡(luò)通信,Gateway和Worker兩兩間註冊(cè)通信地址,所以非常方便的進(jìn)行分散式部署,如果業(yè)務(wù)處理量大可以單純的增加Worker服務(wù)。
它們有一個(gè)負(fù)責(zé)監(jiān)聽的父進(jìn)程(Master),監(jiān)聽子進(jìn)程狀態(tài),發(fā)送 signal 給子進(jìn)程,接受來(lái)自終端的命令、信號(hào)等工作。父進(jìn)程可以說是整個(gè)系統(tǒng)啟動(dòng)後的入口。
啟動(dòng)命令解析
既然以命令模式(cli)運(yùn)行(注意與fpm 的區(qū)別,後者處理來(lái)自網(wǎng)頁(yè)端的請(qǐng)求) ,就必然有一個(gè)啟動(dòng)腳本解析命令,譬如說3.x版本(之前預(yù)設(shè)為daemon)新增一個(gè)-d 參數(shù),以表示守護(hù)程序運(yùn)行,解析到該參數(shù)設(shè)置self::$daemon = true, 隨後fork子進(jìn)程以脫離目前進(jìn)程組,設(shè)定進(jìn)程組組長(zhǎng)等工作。
這裡有兩個(gè)非常重要的參數(shù)$argc 和$argc,前者表示參數(shù)個(gè)數(shù),後者為一個(gè)數(shù)組,保存有指令的所有參數(shù),例如:sudo php start.php start -d, $argv就是array( [0]=>start.php, [1]=>start, [2]=>-d ),而解析主要用到$argv。
啟動(dòng)主要執(zhí)行下列步驟:
1、包含自動(dòng)載入器Autoloader?,載入各Application 下啟動(dòng)檔案;
2、設(shè)定?_appInitPath 根目錄;
3、解析,初始化參數(shù),執(zhí)行對(duì)應(yīng)指令。
下面是具體實(shí)作(workerman/worker.php):
public static function parseCommand() { // 檢查運(yùn)行命令的參數(shù) global $argv; $start_file = $argv[0]; // 命令 $command = trim($argv[1]); // 子命令,目前只支持-d $command2 = isset($argv[2]) ? $argv[2] : ''; // 檢查主進(jìn)程是否在運(yùn)行 $master_pid = @file_get_contents(self::$pidFile); $master_is_alive = $master_pid && @posix_kill($master_pid, 0); if($master_is_alive) { if($command === 'start') { self::log("Workerman[$start_file] is running"); } } elseif($command !== 'start' && $command !== 'restart') { self::log("Workerman[$start_file] not run"); } // 根據(jù)命令做相應(yīng)處理 switch($command) { // 啟動(dòng) workerman case 'start': if($command2 === '-d') { Worker::$daemonize = true; } break; // 顯示 workerman 運(yùn)行狀態(tài) case 'status': exit(0); // 重啟 workerman case 'restart': // 停止 workeran case 'stop': // 想主進(jìn)程發(fā)送SIGINT信號(hào),主進(jìn)程會(huì)向所有子進(jìn)程發(fā)送SIGINT信號(hào) $master_pid && posix_kill($master_pid, SIGINT); // 如果 $timeout 秒后主進(jìn)程沒有退出則展示失敗界面 $timeout = 5; $start_time = time(); while(1) { // 檢查主進(jìn)程是否存活 $master_is_alive = $master_pid && posix_kill($master_pid, 0); if($master_is_alive) { // 檢查是否超過$timeout時(shí)間 if(time() - $start_time >= $timeout) { self::log("Workerman[$start_file] stop fail"); exit; } usleep(10000); continue; } self::log("Workerman[$start_file] stop success"); // 是restart命令 if($command === 'stop') { exit(0); } // -d 說明是以守護(hù)進(jìn)程的方式啟動(dòng) if($command2 === '-d') { Worker::$daemonize = true; } break; } break; // 平滑重啟 workerman case 'reload': exit; } }
walker程式碼註解已經(jīng)非常詳盡,下面有幾點(diǎn)細(xì)節(jié):
1、檢查主進(jìn)程是否存活:17行的邏輯與操作,如果主進(jìn)程PID存在情況下,向該進(jìn)程發(fā)送信號(hào)0,實(shí)際上並沒有發(fā)送任何訊息,只是檢測(cè)該進(jìn)程(或進(jìn)程組)是否存活,同時(shí)也檢測(cè)當(dāng)前用戶是否有權(quán)限發(fā)送系統(tǒng)訊號(hào);
2、為什麼主程序PID會(huì)保存?系統(tǒng)啟動(dòng)後脫離目前terminal運(yùn)行,如果要執(zhí)行關(guān)閉或其他指令,此時(shí)是以另外的一個(gè)程序執(zhí)行該指令,如果我們連進(jìn)程PID都不知道,那該向誰(shuí)發(fā)訊號(hào)呢?
所以主進(jìn)程PID必須保存起來(lái),而且主進(jìn)程負(fù)責(zé)監(jiān)聽其他子進(jìn)程,所以它是我們繼續(xù)操作的入口。
Worker::runAll()
#php的socket程式設(shè)計(jì)其實(shí)和C差不多,後者對(duì)socket進(jìn)行了再包裹,並提供介面給php,在php下網(wǎng)路程式設(shè)計(jì)步驟大幅減少。
譬如:stream_socket_server?和?stream_socket_client?直接建立了server/client socke(php有兩套socket運(yùn)算子)。 wm則大量使用了前者,啟動(dòng)過程如下(註釋已經(jīng)非常詳盡):
public static function runAll() { // 初始化環(huán)境變量 self::init(); // 解析命令 self::parseCommand(); // 嘗試以守護(hù)進(jìn)程模式運(yùn)行 self::daemonize(); // 初始化所有worker實(shí)例,主要是監(jiān)聽端口 self::initWorkers(); // 初始化所有信號(hào)處理函數(shù) self::installSignal(); // 保存主進(jìn)程pid self::saveMasterPid(); // 創(chuàng)建子進(jìn)程(worker進(jìn)程)并運(yùn)行 self::forkWorkers(); // 展示啟動(dòng)界面 self::displayUI(); // 嘗試重定向標(biāo)準(zhǔn)輸入輸出 self::resetStd(); // 監(jiān)控所有子進(jìn)程(worker進(jìn)程) self::monitorWorkers(); }
下面還是只說該過程的關(guān)鍵點(diǎn):
1、始化環(huán)境變量,例如設(shè)定主行程名稱、日誌路徑,初始化計(jì)時(shí)器等等;
2、解析命令列參數(shù),主要用到$argc 和$argc 用法同C語(yǔ)言;
3、產(chǎn)生守護(hù)進(jìn)程,以脫離當(dāng)前終端(兩年前大部分認(rèn)為PHP無(wú)法做daemon,其實(shí)這是個(gè)誤區(qū)!其實(shí)PHP在linux的進(jìn)程模型很穩(wěn)定,現(xiàn)在wm在商業(yè)的應(yīng)用已經(jīng)非常成熟,國(guó)內(nèi)某公司每天處理幾億的連接,用於訂單、支付調(diào)用,大家可以打消顧慮了);
4、初始化所有worker實(shí)例(注意,這裡是在主進(jìn)程做的,只是生成了一堆server 並沒有設(shè)定監(jiān)聽,多進(jìn)程模型是子程序做的監(jiān)聽,即IO復(fù)用);
5、為主程序註冊(cè)訊號(hào)處理函數(shù);
6、保存主進(jìn)程PID,當(dāng)系統(tǒng)運(yùn)行後,我們?cè)诮K端查看系統(tǒng)狀態(tài)或執(zhí)行關(guān)閉、重啟命令,是透過主進(jìn)程進(jìn)行通信,所以需要知道主進(jìn)程PID,我們知道在終端下敲入一個(gè)可執(zhí)行指令,實(shí)則是在目前終端機(jī)下新建一個(gè)子程序來(lái)執(zhí)行,所以我們需要得知主程序PID,以向WM主程序發(fā)送SIGNAL,這時(shí)訊號(hào)處理函數(shù)會(huì)擷取該訊號(hào),並透過回呼方式執(zhí)行。
7、建立子進(jìn)程,設(shè)定目前進(jìn)程使用者(root)。在多進(jìn)程模型中,兩類子進(jìn)程,分別監(jiān)聽不同的server位址,我們?cè)谥鬟M(jìn)程只是建立server並沒有設(shè)定監(jiān)聽,也沒有產(chǎn)生指定數(shù)目的server。
原因在於,我們?cè)谝粋€(gè)進(jìn)程多次創(chuàng)建同一個(gè)socket,會(huì)報(bào)錯(cuò), worker數(shù)目其實(shí)就是socket 數(shù)量,也就是該socket 的子進(jìn)程數(shù)目,子進(jìn)程繼承了父進(jìn)程上下文,但是只監(jiān)聽特定的socket 事件;
8、在子進(jìn)程中,將server socket 註冊(cè)監(jiān)聽事件,用到一個(gè)擴(kuò)展Event,可以實(shí)現(xiàn)IO復(fù)用,並註冊(cè)資料讀取回調(diào),同時(shí)也可註冊(cè)socket連接事件回調(diào);
9、輸入輸出重定向;
10、主程序監(jiān)聽子程序狀態(tài),在一個(gè)無(wú)限迴圈中呼叫pcntl_signal_dispatch() 函數(shù),用於擷取子程序退出狀態(tài),函數(shù)會(huì)一直阻塞,直到有子程序退出時(shí)才觸發(fā);
更多workerman相關(guān)知識(shí)請(qǐng)關(guān)注workerman教學(xué)欄位。
以上是workerman源碼分析之啟動(dòng)過程詳解的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁(yè)開發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)

實(shí)現(xiàn)Workerman文件中的文件上傳與下載,需要具體程式碼範(fàn)例引言:Workerman是一款高效能的PHP非同步網(wǎng)路通訊框架,具備簡(jiǎn)潔、高效、易用等特點(diǎn)。在實(shí)際開發(fā)中,文件上傳和下載是常見的功能需求,本文將介紹如何使用Workerman框架實(shí)現(xiàn)文件的上傳和下載,並給出具體的程式碼範(fàn)例。一、檔案上傳:檔案上傳是指將本機(jī)上的檔案?jìng)鬏斨了欧鞫说牟僮?。下面是使?/p>

Swoole 和 Workerman 都是高效能 PHP 伺服器框架。 Swoole 以其非同步處理、出色的效能和可擴(kuò)展性而聞名,適用於需要處理大量並發(fā)請(qǐng)求和高吞吐量的專案。 Workerman 提供了非同步和同步模式的靈活性,具有直覺的 API,更適合易用性和處理較低並發(fā)量的專案。

如何實(shí)現(xiàn)Workerman文件的基本使用方法簡(jiǎn)介:Workerman是一個(gè)高效能的PHP開發(fā)框架,它可以幫助開發(fā)者輕鬆建立高並發(fā)的網(wǎng)路應(yīng)用程式。本文將介紹Workerman的基本使用方法,包括安裝和設(shè)定、建立服務(wù)和監(jiān)聽連接埠、處理客戶端請(qǐng)求等。並給出相應(yīng)的程式碼範(fàn)例。一、安裝並設(shè)定Workerman在命令列中輸入以下命令來(lái)安裝Workerman:c

如何實(shí)現(xiàn)Workerman文件中的定時(shí)器功能Workerman是一款強(qiáng)大的PHP非同步網(wǎng)路通訊框架,它提供了豐富的功能,其中就包括定時(shí)器功能。使用定時(shí)器可以在指定的時(shí)間間隔內(nèi)執(zhí)行程式碼,非常適合定時(shí)任務(wù)、輪詢等應(yīng)用程式場(chǎng)景。接下來(lái),我將詳細(xì)介紹如何在Workerman中實(shí)現(xiàn)定時(shí)器功能,並提供具體的程式碼範(fàn)例。第一步:安裝Workerman首先,我們需要安裝Worker

如何實(shí)現(xiàn)Workerman文件中的反向代理功能,需要具體程式碼範(fàn)例簡(jiǎn)介:Workerman是一款高效能的PHP多進(jìn)程網(wǎng)路通訊框架,提供了豐富的功能和強(qiáng)大的效能,廣泛應(yīng)用於Web即時(shí)通訊、長(zhǎng)連接服務(wù)等場(chǎng)景。其中,Workerman也支援反向代理功能,可實(shí)現(xiàn)伺服器對(duì)外提供服務(wù)時(shí)的負(fù)載平衡和靜態(tài)資源快取等功能。本篇文章將介紹如何使用Workerman實(shí)現(xiàn)反向代理功

Workerman開發(fā):基於UDP協(xié)議的即時(shí)視訊通話摘要:本文將介紹如何使用Workerman框架實(shí)現(xiàn)基於UDP協(xié)議的即時(shí)視訊通話功能。我們將深入了解UDP協(xié)議的特點(diǎn),並透過程式碼範(fàn)例展示如何建立一個(gè)簡(jiǎn)單但完整的即時(shí)視訊通話應(yīng)用程式。引言:在網(wǎng)路通訊中,即時(shí)視訊通話是一項(xiàng)非常重要的功能。傳統(tǒng)的TCP協(xié)定在實(shí)現(xiàn)即時(shí)性較高的視訊通話時(shí),可能會(huì)有傳輸延遲等問題。而UDP

如何使用Workerman建立高可用性負(fù)載平衡系統(tǒng),需要具體程式碼範(fàn)例在現(xiàn)代技術(shù)領(lǐng)域中,隨著網(wǎng)路的快速發(fā)展,越來(lái)越多的網(wǎng)站和應(yīng)用程式需要處理大量的並發(fā)請(qǐng)求。為了實(shí)現(xiàn)高可用性和高效能,負(fù)載平衡系統(tǒng)成為了必不可少的組件之一。本文將介紹如何使用PHP開源框架Workerman建構(gòu)一個(gè)高可用性的負(fù)載平衡系統(tǒng),並提供具體的程式碼範(fàn)例。一、Workerman簡(jiǎn)介Worke

Workerman是基於PHP開發(fā)的高效能非同步事件驅(qū)動(dòng)框架,它可以輕鬆實(shí)現(xiàn)TCP/UDP協(xié)定下的長(zhǎng)連線開發(fā)。除此之外,Workerman也提供了實(shí)現(xiàn)檔案?jìng)鬏數(shù)墓δ?,可以用於大檔案?jìng)鬏?、資料備份等場(chǎng)景。本文將介紹如何在Workerman中實(shí)現(xiàn)檔案?jìng)鬏敼δ?,並提供具體的程式碼範(fàn)例。一、文件上傳功能實(shí)現(xiàn)文件上傳功能需要客戶端將要上傳的文件傳送給服務(wù)端,服務(wù)端驗(yàn)證
