WorkerMan::Worker类解析(3)

    // 把运行的脚本变为守护进程
    protected static function daemonize()
    {
        if (!self::$daemonize) {
            return;
        }
        umask(0);
        // 创建子进程.
        $pid = pcntl_fork();
        if (-1 === $pid) {
            throw new Exception('fork fail');
        } elseif ($pid > 0) {
            // 结束父进程.
            exit(0);
        }
        // 使当前子进程成为会话组长.
        if (-1 === posix_setsid()) {
            throw new Exception("setsid fail");
        }
        // Fork again avoid SVR4 system regain the control of terminal.
        // 再次fork子进程,使进程完全脱离终端,成为守护进程.
        $pid = pcntl_fork();
        if (-1 === $pid) {
            throw new Exception("fork fail");
        } elseif (0 !== $pid) {
            exit(0);
        }
    }

核心代码:
$pid = pcntl_fork();
posix_setsid()
$pid = pcntl_fork();
    // 初始化worker数据.
    protected static function initWorkers()
    {
        // 遍历所有的worker.
        foreach (self::$_workers as $worker) {
            // 如果worker名字不存在,则给予一个初始值.
            if (empty($worker->name)) {
                $worker->name = 'none';
            }

            // 获取最大的worker名称长度.
            $worker_name_length = strlen($worker->name);
            if (self::$_maxWorkerNameLength < $worker_name_length) {
                self::$_maxWorkerNameLength = $worker_name_length;
            }

            // 获取最长的socket名称长度.
            $socket_name_length = strlen($worker->getSocketName());
            if (self::$_maxSocketNameLength < $socket_name_length) {
                self::$_maxSocketNameLength = $socket_name_length;
            }

            // Get unix user of the worker process.
            // 如果运行用户没有设置,那么把当前运行用户作为运行用户.
            if (empty($worker->user)) {
                $worker->user = self::getCurrentUser();
            } else {
                // 如果不是root用户,并且设置的用户和当前运行脚本用户不匹配,则给出一个警告信息.
                // posix_getuid() 获取当前运行用户的id, root用户的id=0.
                if (posix_getuid() !== 0 && $worker->user != self::getCurrentUser()) {
                    self::log('Warning: You must have the root privileges to change uid and gid.');
                }
            }

            // Get maximum length of unix user name.
            $user_name_length = strlen($worker->user);
            if (self::$_maxUserNameLength < $user_name_length) {
                self::$_maxUserNameLength = $user_name_length;
            }

            // Listen.
            // 创建worker监听.
            if (!$worker->reusePort) {
                $worker->listen();
            }
        }
    }

1. posix_getuid() 获取运行脚本的当前uid (root用户的uid=0)

    // 获取当前运行脚本的用户名.
    protected static function getCurrentUser()
    {
        // 获取当前运行用户的用户名.
        // posix_getpwuid 根据用户id获取用户信息.
        $user_info = posix_getpwuid(posix_getuid());
        return $user_info['name'];
    }

1. posix_getpwuid() 根据用户的uid获取用户的信息.
    // worker进行监听.
    public function listen()
    {
        if (!$this->_socketName) {
            return;
        }

        // Autoload.
        // 设置自动加载路径.
        Autoloader::setRootPath($this->_autoloadRootPath);

        if (!$this->_mainSocket) {
            // Get the application layer communication protocol and listening address.
            // 切割出协议和地址.
            list($scheme, $address) = explode(':', $this->_socketName, 2);
            // Check application layer protocol class.
            // 是否为内置协议,不是内置协议需要加载协议的定义.
            if (!isset(self::$_builtinTransports[$scheme])) {
                $scheme         = ucfirst($scheme);
                /**
                 * 协议可能存在的目录.
                 * Project\Protocols\...
                 * Project\WorkerMan\Protocols\...
                 */
                $this->protocol = '\\Protocols\\' . $scheme;
                if (!class_exists($this->protocol)) {
                    $this->protocol = "\\Workerman\\Protocols\\$scheme";
                    // 自定义协议处理不存在,抛出错误.
                    if (!class_exists($this->protocol)) {
                        throw new Exception("class \\Protocols\\$scheme not exist");
                    }
                }

                // 自定义的协议默认都走tcp.
                if (!isset(self::$_builtinTransports[$this->transport])) {
                    throw new \Exception('Bad worker->transport ' . var_export($this->transport, true));
                }
            } else {
                $this->transport = $scheme;
            }

            $local_socket = self::$_builtinTransports[$this->transport] . ":" . $address;

            // Flag.
            $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
            $errno = 0;
            $errmsg = '';
            // SO_REUSEPORT.
            // 端口复用-php7才能使用.
            if ($this->reusePort) {
                stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1);
            }

            // Create an Internet or Unix domain server socket.
            // 创建服务端server的socket监听.
            $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context);
            if (!$this->_mainSocket) {
                throw new Exception($errmsg);
            }

            if ($this->transport === 'ssl') {
                stream_socket_enable_crypto($this->_mainSocket, false);
            } elseif ($this->transport === 'unix') {
                $socketFile = substr($address, 2);
                if ($this->user) {
                    chown($socketFile, $this->user);
                }
                if ($this->group) {
                    chgrp($socketFile, $this->group);
                }
            }

            // Try to open keepalive for tcp and disable Nagle algorithm.
            //
            if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') {
                // 将stream转换为socket对象.
                $socket = socket_import_stream($this->_mainSocket);
                // 设置socket属性keepalive和禁用Nagle.
                @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
                @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);
            }

            // 非阻塞模式.
            stream_set_blocking($this->_mainSocket, 0);
        }

        // 注册监听(self::$globalEvent但是这里此变量=null,所有是不会执行的).
        $this->resumeAccept();
    }

1. $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); // 创建socket监听
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值