PHP Ev 事件扩展如何监听嵌套的事件??

Linux 使用 PHP Ev 扩展,监听 socket

这边有两个递进的监听:

  1. 监听客户端连接
  2. 客户端连接后,监听客户端进行收发数据

具体实现代码如下:

<?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("所有进程都已经退出");

运行后发现,如果有客户端连接,则触发回调函数,但是,如果该客户端发送了数据到服务器,却没有触发回调。

不知道该如何破解??

阅读 3.5k
1 个回答

EvIo 有些特性:

  • 同作用域下,同类事件会相互覆盖,后面定义的覆盖前面的
  • 嵌套事件,需要再次执行 Ev::run 才会触发,再次调用 Ev::run 后事件的执行不可预测。

基于上面两个,我发现了一个特殊的现象:

function login($fd , $flag , $callback , $args){
    return new EvIo($fd , $flag , $callback , $args);
}

// 这种方式定义多个重复事件,都会触发 ..
// 无语,但是目前就是用这种方式投入使用的
$one = login($socket , Ev::READ , null , null);
$two = login($socket , Ev::READ , null , null);

// 跑进程
Ev::run();
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏