鍍金池/ 問答/PHP  C  數(shù)據(jù)庫/ PHP Ev 事件擴(kuò)展如何監(jiān)聽嵌套的事件??

PHP Ev 事件擴(kuò)展如何監(jiān)聽嵌套的事件??

Linux 使用 PHP Ev 擴(kuò)展,監(jiān)聽 socket。

這邊有兩個(gè)遞進(jìn)的監(jiān)聽:

  1. 監(jiān)聽客戶端連接
  2. 客戶端連接后,監(jiān)聽客戶端進(jìn)行收發(fā)數(shù)據(jù)

具體實(shí)現(xiàn)代碼如下:

<?php


$tcp    = "127.0.0.1:9005";
$count  = 2;
$pids   = [];

// 端口多進(jìn)程監(jiān)聽
for ($i = 0; $i < $count; ++$i)
{
    $pid = pcntl_fork();

    if ($pid < 0) {
        exit('生成子進(jìn)程失敗\n');
    } else if ($pid > 0) {
        // 父進(jìn)程
        $pids[] = $pid;
    } else {
        var_dump("產(chǎn)生子進(jìn)程 {$i}");

        // 創(chuàng)建資源流上下文
        $context = stream_context_create([
            'socket' => [
                //
                'backlog' => 102400
            ]
        ]);

        // 設(shè)置端口重用
        stream_context_set_option($context , 'socket' , 'so_reuseport' , 1);

        // 監(jiān)聽客戶端鏈接 + 設(shè)置端口重用
        $server = stream_socket_server($tcp , $errno , $errstr , STREAM_SERVER_BIND | STREAM_SERVER_LISTEN , $context);
        $clients = [];

        // 如果資源可讀,讀取,并且一直監(jiān)聽
        $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;

            // 設(shè)置資源阻塞模式
            stream_set_blocking($client , false);

            // 事件監(jiān)聽
            $ev = new EvIO($client , Ev::READ | Ev::WRITE , function($watcher) use($client , $clients){
                var_dump($watcher->fd === $client);

                var_dump("客戶端資源可讀!!");
            });

            var_dump("監(jiān)聽客戶端數(shù)據(jù)收發(fā)已經(jīng)就緒");
        });

        // 開始事件監(jiān)聽!
        Ev::run();

        // 不要進(jìn)入父進(jìn)程領(lǐng)域
        exit;
    }
}

foreach ($pids as $v)
{
    pcntl_waitpid($v , $status , WUNTRACED);
}

var_dump("所有進(jìn)程都已經(jīng)退出");

運(yùn)行后發(fā)現(xiàn),如果有客戶端連接,則觸發(fā)回調(diào)函數(shù),但是,如果該客戶端發(fā)送了數(shù)據(jù)到服務(wù)器,卻沒有觸發(fā)回調(diào)。

不知道該如何破解??

回答
編輯回答
初念

EvIo 有些特性:

  • 同作用域下,同類事件會(huì)相互覆蓋,后面定義的覆蓋前面的
  • 嵌套事件,需要再次執(zhí)行 Ev::run 才會(huì)觸發(fā),再次調(diào)用 Ev::run 后事件的執(zhí)行不可預(yù)測。

基于上面兩個(gè),我發(fā)現(xiàn)了一個(gè)特殊的現(xiàn)象:

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

// 這種方式定義多個(gè)重復(fù)事件,都會(huì)觸發(fā) ..
// 無語,但是目前就是用這種方式投入使用的
$one = login($socket , Ev::READ , null , null);
$two = login($socket , Ev::READ , null , null);

// 跑進(jìn)程
Ev::run();
2018年5月12日 18:09