类别:Workerman / 日期:2019-11-27 / 浏览:188 / 评论:0


workerman

版本:3.1.8(linux)

模子:GatewayWorker(Worker模子可与之类比)

注:只贴出解说部份代码,出处以文件名情势给出,人人可自行检察

workerman最初只开发了Linux版本,win是厥后增添的,基于敕令行形式运转(cli)。

多历程模子

事情历程,Master、Gateway和Worker,Gateway重要用于处置惩罚IO事宜,保留客户端链接状况,将数据处置惩罚要求发送给Worker等事情,Worker则是完整的营业逻辑处置惩罚,前者为IO密集型,后者为盘算密集型,它们之间经由历程收集通讯,Gateway和Worker两两间注册通讯地点,所以异常轻易的举行分布式布置,假如营业处置惩罚量大能够纯真的增添Worker效劳。

它们有一个担任监听的父历程(Master),监听子历程状况,发送 signal 给子历程,接收来自终端的敕令、信号等事情。父历程能够说是全部体系启动后的进口。

启动敕令剖析

既然以敕令形式(cli)运转(注重与 fpm 的区分,后者处置惩罚来自网页端的要求),就必定有一个启动剧本剖析敕令,比如说3.x版本(之前默以为daemon)新增一个 -d 参数,以示意保卫历程运转,剖析到该参数设置 self::$daemon = true, 随后fork子历程以离开当前历程组,设置历程组组长等事情。

这里有两个异常重要的参数 $argc 和 $argc,前者示意参数个数,后者为一个数组,保留有敕令的一切参数,比方:sudo php start.php start -d,$argv就是 array( [0]=>start.php, [1]=>start, [2]=>-d ),而剖析重要用到$argv。

启动重要实行下面步骤:

1、包括自动加载器 Autoloader ,加载各 Application 下启动文件;

2、设置 _appInitPath 根目录;

3、剖析,初始化参数,实行响应敕令。

下面是细致完成(workerman/worker.php):

public static function parseCommand()
    {
        // 搜检运转敕令的参数
        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 运转状况
            case 'status':
                exit(0);
            // 重启 workerman
            case 'restart':
            // 住手 workeran
            case 'stop':
                // 想主历程发送SIGINT信号,主历程会向一切子历程发送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代码解释已异常详实,下面有几点细节处:

1、搜检主历程是不是存活:17行的逻辑与操纵,假如主历程PID存在情况下,向该历程发送信号0,实际上并没有发送任何信息,只是检测该历程(或历程组)是不是存活,同时也检测当前用户是不是有权限发送体系信号;

2、为何主历程PID会保留?体系启动后离开当前terminal运转,假如要实行封闭或许其他敕令,此时是以别的的一个历程实行该敕令,假如我们连历程PID都不晓得,那该向谁发信号呢?

所以主历程PID必需保留起来,而且主历程担任监听其他子历程,所以它是我们继续操纵的进口。

Worker::runAll()

php的socket编程实在和C差不多,后者对socket举行了再包裹,并供应接口给php,在php下收集编程步骤大大削减。

比如:stream_socket_server 和 stream_socket_client 直接建立了server/client socke(php有两套socket操纵函数)。wm则大批使用了前者,启动历程以下(解释已异常详实):

public static function runAll()
    {
        // 初始化环境变量
        self::init();
        // 剖析敕令
        self::parseCommand();
        // 尝试以保卫历程形式运转
        self::daemonize();
        // 初始化一切worker实例,重如果监听端口
        self::initWorkers();
        //  初始化一切信号处置惩罚函数
        self::installSignal();
        // 保留主历程pid
        self::saveMasterPid();
        // 建立子历程(worker历程)并运转
        self::forkWorkers();
        // 展现启动界面
        self::displayUI();
        // 尝试重定向规范输入输出
        self::resetStd();
        // 监控一切子历程(worker历程)
        self::monitorWorkers();
    }

下面照样只说该历程的症结点:

1、始化环境变量,比方设置主历程称号、日记途径,初始化定时器等等;

2、剖析敕令行参数,重要用到 $argc 和 $argc 用法同C言语;

3、生成保卫历程,以离开当前终端(两年前大部份以为PHP没法做daemon,实在这是个误区!实在PHP在linux的历程模子很稳固,如今wm在贸易的运用已异常成熟,国内某公司天天处置惩罚几亿的衔接,用于定单、付出挪用,人人能够消除挂念了);

4、初始化一切worker实例(注重,这里是在主历程做的,只是生成了一堆 server 并没有设置监听,多历程模子是在子历程做的监听,即IO复用);

5、为主历程注册信号处置惩罚函数;

6、保留主历程PID,当体系运转后,我们在终端检察体系状况或许实行封闭、重启敕令,是经由历程主历程举行通讯,所以须要晓得主历程PID,我们晓得在终端下敲入一个可实行敕令,实则是在当前终端下新建一个子历程来实行,所以我们须要得知主历程PID,以向WM主历程发送SIGNAL,这时候信号处置惩罚函数捕捉该信号,并经由历程回调体式格局实行。

7、建立子历程,设置当前历程用户(root)。在多历程模子中,两类子历程,离别监听差别的server地点,我们在主历程只是建立server并没有设置监听,也没有生成指定数目的server。

缘由在于,我们在一个历程屡次建立同一个 socket,会报错, worker数目实在就是 socket 数目,也就是该 socket 的子历程数目,子历程继续了父历程上下文,然则只监听特定的 socket 事宜;

8、在子历程中,将 server socket 注册监听事宜,用到一个扩大Event,能够完成IO复用,并注册数据读取回调,同时也可注册socket衔接事宜回调;

9、输入输出重定向;

10、主历程监听子历程状况,在一个无穷循环中挪用 pcntl_signal_dispatch() 函数,用于捕捉子历程退出状况,该函数会一向壅塞,直到有子历程退出时才触发;

更多workerman相干学问请关注workerman教程栏目。

以上就是workerman源码剖析之启动历程详解的细致内容,更多请关注ki4网别的相干文章!

打赏

感谢您的赞助~

打开支付宝扫一扫,即可进行扫码打赏哦~

版权声明 : 本文未使用任何知识共享协议授权,您可以任何形式自由转载或使用。

 可能感兴趣的文章