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");
}
$pid = pcntl_fork();
if (-1 === $pid) {
throw new Exception("fork fail");
} elseif (0 !== $pid) {
exit(0);
}
}
核心代码:
$pid = pcntl_fork();
posix_setsid()
$pid = pcntl_fork();
protected static function initWorkers()
{
foreach (self::$_workers as $worker) {
if (empty($worker->name)) {
$worker->name = 'none';
}
$worker_name_length = strlen($worker->name);
if (self::$_maxWorkerNameLength < $worker_name_length) {
self::$_maxWorkerNameLength = $worker_name_length;
}
$socket_name_length = strlen($worker->getSocketName());
if (self::$_maxSocketNameLength < $socket_name_length) {
self::$_maxSocketNameLength = $socket_name_length;
}
if (empty($worker->user)) {
$worker->user = self::getCurrentUser();
} else {
if (posix_getuid() !== 0 && $worker->user != self::getCurrentUser()) {
self::log('Warning: You must have the root privileges to change uid and gid.');
}
}
$user_name_length = strlen($worker->user);
if (self::$_maxUserNameLength < $user_name_length) {
self::$_maxUserNameLength = $user_name_length;
}
if (!$worker->reusePort) {
$worker->listen();
}
}
}
1. posix_getuid() 获取运行脚本的当前uid (root用户的uid=0)
protected static function getCurrentUser()
{
$user_info = posix_getpwuid(posix_getuid());
return $user_info['name'];
}
1. posix_getpwuid() 根据用户的uid获取用户的信息.
public function listen()
{
if (!$this->_socketName) {
return;
}
Autoloader::setRootPath($this->_autoloadRootPath);
if (!$this->_mainSocket) {
list($scheme, $address) = explode(':', $this->_socketName, 2);
if (!isset(self::$_builtinTransports[$scheme])) {
$scheme = ucfirst($scheme);
$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");
}
}
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;
$flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$errno = 0;
$errmsg = '';
if ($this->reusePort) {
stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1);
}
$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);
}
}
if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') {
$socket = socket_import_stream($this->_mainSocket);
@socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
@socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);
}
stream_set_blocking($this->_mainSocket, 0);
}
$this->resumeAccept();
}
1. $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context);