Linux
使用 PHP Ev 扩展,监听 socket
。
这边有两个递进的监听:
- 监听客户端连接
- 客户端连接后,监听客户端进行收发数据
具体实现代码如下:
<?php
$tcp = "127.0.0.1:9005";
$count = 2;
$pids = [];
// 端口多进程监听
for ($i = 0; $i < $count; ++$i)
{
$pid = pcntl_fork();
if ($pid < 0) {
exit('生成子进程失败\n');
} else if ($pid > 0) {
// 父进程
$pids[] = $pid;
} else {
var_dump("产生子进程 {$i}");
// 创建资源流上下文
$context = stream_context_create([
'socket' => [
//
'backlog' => 102400
]
]);
// 设置端口重用
stream_context_set_option($context , 'socket' , 'so_reuseport' , 1);
// 监听客户端链接 + 设置端口重用
$server = stream_socket_server($tcp , $errno , $errstr , STREAM_SERVER_BIND | STREAM_SERVER_LISTEN , $context);
$clients = [];
// 如果资源可读,读取,并且一直监听
$ev = new EvIo($server , Ev::READ , function($watcher) use($clients , $server){
var_dump("接收到客户端链接");
var_dump($watcher->fd === $server);
// $client = stream_socket_accept($watcher->fd);
$client = stream_socket_accept($server);
$clients[] = $client;
// 设置资源阻塞模式
stream_set_blocking($client , false);
// 事件监听
$ev = new EvIO($client , Ev::READ | Ev::WRITE , function($watcher) use($client , $clients){
var_dump($watcher->fd === $client);
var_dump("客户端资源可读!!");
});
var_dump("监听客户端数据收发已经就绪");
});
// 开始事件监听!
Ev::run();
// 不要进入父进程领域
exit;
}
}
foreach ($pids as $v)
{
pcntl_waitpid($v , $status , WUNTRACED);
}
var_dump("所有进程都已经退出");
运行后发现,如果有客户端连接,则触发回调函数,但是,如果该客户端发送了数据到服务器,却没有触发回调。
不知道该如何破解??
EvIo
有些特性:Ev::run
才会触发,再次调用Ev::run
后事件的执行不可预测。基于上面两个,我发现了一个特殊的现象: