WorkerMan::Worker类解析(3)

来源:互联网 发布:北塔软件怎么样 编辑:程序博客网 时间:2024/06/05 11:26
    // 把运行的脚本变为守护进程    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监听
原创粉丝点击