http://blog.csdn.net/system1024/article/details/51162372
因业务需要用到了pcntl_fork 处理多客户端连接处理数据的需求
但测试下来出现一个问题:
fork 之后, 若等待子进程返回, 那么程序就会阻塞, 不等待子进程返回, 则会出现僵尸进程
$obj = new service('127.0.0.1', 50000); $obj->run(); class service { private $socket_id; private $socket_cid; private $pid; function __construct($host, $port) { $this->socket_id = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$this->socket_id) { $this->logs("create socket error"); return false; } if (!socket_bind($this->socket_id, $host, $port)) { $this->logs(socket_strerror(socket_last_error())); socket_close($this->socket_id); return false; } if (!socket_listen($this->socket_id)) { $this->logs(socket_strerror(socket_last_error())); socket_close($this->socket_id); return false; } } public function run() { if (!$this->socket_id) { $this->logs("create socket error"); return false; } $this->logs("Starting..."); while (true) { $this->socket_cid = socket_accept($this->socket_id); $ip = ""; socket_getpeername($this->socket_cid, $ip); $this->logs("Client IP: {$ip}"); if (!is_resource($this->socket_cid)) { $this->logs(socket_strerror(socket_last_error())); socket_close($this->socket_id); return false; } $this->pid = pcntl_fork(); if ($this->pid == -1) { $this->logs(socket_strerror(socket_last_error())); socket_close($this->socket_cid); return false; } else if ($this->pid) { $status = 0; $s = pcntl_wait($status, WNOHANG); //等待子进程中断,防止子进程成为僵尸进程, 但这样会阻塞, 意思是只能处理一个客户端连接, 多个进入排队 //$s = pcntl_waitpid(0, $status, WUNTRACED); //如果不等待, 则子进程处理完之后, 没有对其进行处理, 会成为僵尸进程 $this->logs("Status: " . $status . ", pcntl_waitpid: " . $s); } elseif ($this->pid == 0) { //child process $k = 0; while (true) { if ($data = socket_read($this->socket_cid, 1024)) { $this->logs("Read Data: {$data}"); $flag = socket_write($this->socket_cid, date('Y-m-d H:i:s') . '|已收到'); $this->logs("Write Result: {$flag}"); } sleep(1); $k++; $this->logs("Wait...\t" . date('Y-m-d H:i:s')); if ($k > 30) { break; } } socket_close($this->socket_cid); exit(1); } } socket_close($this->socket_id); } /** * 打日志 * @param string $msg * @return int */ private function logs($msg) { $logs_filename = LOGS_PATH; if (!file_exists($logs_filename)) { @mkdir($logs_filename, 0777, true); } $logs_filename .= date('j') . '.log'; $logs_data = date('[H:i:s]') . " {$msg}\n"; return file_put_contents($logs_filename, $logs_data, FILE_APPEND); } function __destruct() { if (is_resource($this->socket_id)) { socket_close($this->socket_id); } if (is_resource($this->socket_cid)) { socket_close($this->socket_cid); } } }
在网上搜了半天, 这位仁兄的解决办法是对的(http://blog.csdn.net/e421083458/article/details/22186475), 就是增加信号处理,
在socket accept之前加上 pcntl_signal(SIGCHLD, SIG_IGN); //如果父进程不关心子进程什么时候结束,子进程结束后,内核会回收。
也就是在run方法开始处 :)
最新评论: