成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

workerman源碼分析之啟動過程詳解-創(chuàng)新互聯(lián)

這篇文章給大家分享的是有關workerman源碼分析之啟動過程詳解的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

公司主營業(yè)務:網站建設、網站設計、移動網站開發(fā)等業(yè)務。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出果洛州免費做網站回饋大家。

workerman

版本:3.1.8(linux)

模型:GatewayWorker(Worker模型可與之類比)

注:只貼出講解部分代碼,出處以文件名形式給出,大家可自行查看

workerman最初只開發(fā)了Linux版本,win是后來增加的,基于命令行模式運行(cli)。

多進程模型

工作進程,Master、Gateway和Worker,Gateway主要用于處理IO事件,保存客戶端鏈接狀態(tài),將數(shù)據處理請求發(fā)送給Worker等工作,Worker則是完全的業(yè)務邏輯處理,前者為IO密集型,后者為計算密集型,它們之間通過網絡通信,Gateway和Worker兩兩間注冊通信地址,所以非常方便的進行分布式部署,如果業(yè)務處理量大可以單純的增加Worker服務。

workerman源碼分析之啟動過程詳解

它們有一個負責監(jiān)聽的父進程(Master),監(jiān)聽子進程狀態(tài),發(fā)送 signal 給子進程,接受來自終端的命令、信號等工作。父進程可以說是整個系統(tǒng)啟動后的入口。

啟動命令解析

既然以命令模式(cli)運行(注意與 fpm 的區(qū)別,后者處理來自網頁端的請求),就必然有一個啟動腳本解析命令,譬如說3.x版本(之前默認為daemon)新增一個 -d 參數(shù),以表示守護進程運行,解析到該參數(shù)設置 self::$daemon = true, 隨后fork子進程以脫離當前進程組,設置進程組組長等工作。

這里有兩個非常重要的參數(shù) $argc 和 $argc,前者表示參數(shù)個數(shù),后者為一個數(shù)組,保存有命令的所有參數(shù),比如:sudo php start.php start -d,$argv就是 array( [0]=>start.php, [1]=>start, [2]=>-d ),而解析主要用到$argv。

啟動主要執(zhí)行下面步驟:

1、包含自動加載器 Autoloader ,加載各 Application 下啟動文件;

2、設置 _appInitPath 根目錄;

3、解析,初始化參數(shù),執(zhí)行相應命令。

下面是具體實現(xiàn)):

public static function parseCommand()
    {
        // 檢查運行命令的參數(shù)
        global $argv;
        $start_file = $argv[0]; 

        // 命令
        $command = trim($argv[1]);
        
        // 子命令,目前只支持-d
        $command2 = isset($argv[2]) ? $argv[2] : '';
        
        // 檢查主進程是否在運行
        $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");
        }
        
        // 根據命令做相應處理
        switch($command)
        {
            // 啟動 workerman
            case 'start':
                if($command2 === '-d')
                {
                    Worker::$daemonize = true;
                }
                break;
            // 顯示 workerman 運行狀態(tài)
            case 'status':
                exit(0);
            // 重啟 workerman
            case 'restart':
            // 停止 workeran
            case 'stop':
                // 想主進程發(fā)送SIGINT信號,主進程會向所有子進程發(fā)送SIGINT信號
                $master_pid && posix_kill($master_pid, SIGINT);
                // 如果 $timeout 秒后主進程沒有退出則展示失敗界面
                $timeout = 5;
                $start_time = time();
                while(1)
                {
                    // 檢查主進程是否存活
                    $master_is_alive = $master_pid && posix_kill($master_pid, 0);
                    if($master_is_alive)
                    {
                        // 檢查是否超過$timeout時間
                        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 說明是以守護進程的方式啟動
                    if($command2 === '-d')
                    {
                        Worker::$daemonize = true;
                    }
                    break;
                }
                break;
            // 平滑重啟 workerman
            case 'reload':
                exit;
        }
    }

walker代碼注釋已經非常詳盡,下面有幾點細節(jié)處:

1、檢查主進程是否存活:17行的邏輯與操作,如果主進程PID存在情況下,向該進程發(fā)送信號0,實際上并沒有發(fā)送任何信息,只是檢測該進程(或進程組)是否存活,同時也檢測當前用戶是否有權限發(fā)送系統(tǒng)信號;

2、為什么主進程PID會保存?系統(tǒng)啟動后脫離當前terminal運行,如果要執(zhí)行關閉或者其他命令,此時是以另外的一個進程執(zhí)行該命令,如果我們連進程PID都不知道,那該向誰發(fā)信號呢?

所以主進程PID必須保存起來,而且主進程負責監(jiān)聽其他子進程,所以它是我們繼續(xù)操作的入口。

Worker::runAll()

php的socket編程其實和C差不多,后者對socket進行了再包裹,并提供接口給php,在php下網絡編程步驟大大減少。

譬如:stream_socket_server 和 stream_socket_client 直接創(chuàng)建了server/client socke(php有兩套socket操作函數(shù))。wm則大量使用了前者,啟動過程如下(注釋已經非常詳盡):

public static function runAll()
    {
        // 初始化環(huán)境變量
        self::init();
        // 解析命令
        self::parseCommand();
        // 嘗試以守護進程模式運行
        self::daemonize();
        // 初始化所有worker實例,主要是監(jiān)聽端口
        self::initWorkers();
        //  初始化所有信號處理函數(shù)
        self::installSignal();
        // 保存主進程pid
        self::saveMasterPid();
        // 創(chuàng)建子進程(worker進程)并運行
        self::forkWorkers();
        // 展示啟動界面
        self::displayUI();
        // 嘗試重定向標準輸入輸出
        self::resetStd();
        // 監(jiān)控所有子進程(worker進程)
        self::monitorWorkers();
    }

下面還是只說該過程的關鍵點:

1、始化環(huán)境變量,例如設置主進程名稱、日志路徑,初始化定時器等等;

2、解析命令行參數(shù),主要用到 $argc 和 $argc 用法同C語言;

3、生成守護進程,以脫離當前終端(兩年前大部分認為PHP無法做daemon,其實這是個誤區(qū)!其實PHP在linux的進程模型很穩(wěn)定,現(xiàn)在wm在商業(yè)的應用已經非常成熟,國內某公司每天處理幾億的連接,用于訂單、支付調用,大家可以打消顧慮了);

4、初始化所有worker實例(注意,這里是在主進程做的,只是生成了一堆 server 并沒有設置監(jiān)聽,多進程模型是在子進程做的監(jiān)聽,即IO復用);

5、為主進程注冊信號處理函數(shù);

6、保存主進程PID,當系統(tǒng)運行后,我們在終端查看系統(tǒng)狀態(tài)或者執(zhí)行關閉、重啟命令,是通過主進程進行通信,所以需要知道主進程PID,我們知道在終端下敲入一個可執(zhí)行命令,實則是在當前終端下新建一個子進程來執(zhí)行,所以我們需要得知主進程PID,以向WM主進程發(fā)送SIGNAL,這時信號處理函數(shù)捕獲該信號,并通過回調方式執(zhí)行。

7、創(chuàng)建子進程,設置當前進程用戶(root)。在多進程模型中,兩類子進程,分別監(jiān)聽不同的server地址,我們在主進程只是創(chuàng)建server并沒有設置監(jiān)聽,也沒有生成指定數(shù)目的server。

原因在于,我們在一個進程多次創(chuàng)建同一個 socket,會報錯, worker數(shù)目其實就是 socket 數(shù)量,也就是該 socket 的子進程數(shù)目,子進程繼承了父進程上下文,但是只監(jiān)聽特定的 socket 事件;

8、在子進程中,將 server socket 注冊監(jiān)聽事件,用到一個擴展Event,可以實現(xiàn)IO復用,并注冊數(shù)據讀取回調,同時也可注冊socket連接事件回調;

9、輸入輸出重定向;

10、主進程監(jiān)聽子進程狀態(tài),在一個無限循環(huán)中調用 pcntl_signal_dispatch() 函數(shù),用于捕獲子進程退出狀態(tài),該函數(shù)會一直阻塞,直到有子進程退出時才觸發(fā);

感謝各位的閱讀!關于“workerman源碼分析之啟動過程詳解”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

本文名稱:workerman源碼分析之啟動過程詳解-創(chuàng)新互聯(lián)
分享網址:http://jinyejixie.com/article38/dijopp.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供動態(tài)網站、網站改版、企業(yè)建站面包屑導航、做網站、網站收錄

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

h5響應式網站建設
郑州市| 牙克石市| 弥渡县| 河北省| 湘潭市| 易门县| 图们市| 阳信县| 祁阳县| 政和县| 通化市| 繁峙县| 渭南市| 阳信县| 鞍山市| 乃东县| 永胜县| 浠水县| 阿坝| 阿坝| 宜宾县| 南乐县| 黄平县| 石楼县| 闽清县| 平武县| 岱山县| 岳阳县| 麻栗坡县| 金湖县| 万州区| 石景山区| 民县| 沈丘县| 监利县| 阿瓦提县| 交口县| 原平市| 保德县| 格尔木市| 阿拉善右旗|