关于异步tcp的问题

小阳光
  • 异步tcp我认为的是,tcp请求会做到异步化,tcp发起请求后,程序自己可以处理其他业务,tcp有结果了就执行回调函数,但是通过我的实验并不是。不知道是我代码有问题还是怎么回事,求解答。

    $task = new Worker();
    $task->onWorkerStart = function ($task) {
    $connection_to_baidu = new AsyncTcpConnection('tcp://xx.xx.xx.xxx:80');
    $connection_to_baidu->onConnect = function ($connection_to_baidu) {
        echo "connect success\n";
        $connection_to_baidu->send("GET /Mapi/v3/Test/test HTTP/1.1\r\nHost: xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
    };
    $connection_to_baidu->onMessage = function ($connection_to_baidu, $http_buffer) {
        echo $http_buffer;
    };
    $connection_to_baidu->onClose = function ($connection_to_baidu) {
        echo "connection closed\n";
    };
    $connection_to_baidu->onError = function ($connection_to_baidu, $code, $msg) {
        echo "Error code:$code msg:$msg\n";
    };
    $connection_to_baidu->connect(); //通过抓包分析,此处会与服务器三次握手
    
    //模拟处理正常其他业务 此处业务耗时大于3秒
    for ($i = 0; $i < 30000; $i++) {
        echo $i . PHP_EOL;
        file_get_contents('workerman.log'); //为了防止此处,一直占用cpu资源,做io操作,让cpu有机会去执行回调函数
    }
    //此时会打印connect success, 抓包此处才会发起http请求   发送$connection_to_baidu->send("GET /Mapi/v3/Test/test HTTP/1.1\r\nHost: xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
    //因为接口sleep睡眠了三秒返回,此处会有大概三秒等待,然后会执行onMessage回调函数 打印结果到控制台
    };
    // 运行worker
    Worker::runAll();
1891 2 1
2个回答

walkor

workerman运行可以认为分为2个状态,一个是执行业务状态,一个是workerman内核态状态,2个状态是串行的,并不会并发执行。

执行业务状态也就是进程在运行业务代码时的状态,这时候workerman内核没有控制权;
workerman内核状态是业务执行完毕后交出控制权后workerman内核运行的状态;

workerman内核状态实际上就是一个event-loop,会监听操作系统发送给workerman的连接事件、连接可读可写、关闭事件,并触发onConnect、onMessage、onClose等。只有在workerman内核态才能接收到这些事件,在执行业务状态无法接收并触发这些事件。

这就很好的解释了为什么上面的代码为什么在业务代码执行完毕后才真正发出了请求。

如果你想要在执行业务逻辑的时候通知其它进程同步处理业务逻辑,你应该用同步的方式发起连接和数据,然后在需要数据的时候读取它。代码类似这样:

$task = new Worker();
$task->onWorkerStart = function ($task) {
    $socket = stream_socket_client('tcp://xx.xx.xx.xxx:80');
    fwrite($socket, "GET /Mapi/v3/Test/test HTTP/1.1\r\nHost: xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");

    //模拟处理正常其他业务 此处业务耗时大于3秒
    for ($i = 0; $i < 30000; $i++) {
        echo $i . PHP_EOL;
        file_get_contents('workerman.log'); //为了防止此处,一直占用cpu资源,做io操作,让cpu有机会去执行回调函数
    }

    echo fread($socket, 8192);
};
// 运行worker
Worker::runAll();

这样在你处理业务的时候,远处的进程也在处理。当你需要获得结果的时候,用fread阻塞等待获得结果即可。

如果你想同步的方式发起请求,异步的方式获得结果,可以用下面的方法。

use Workerman\Connection\TcpConnection;
$task = new Worker();
$task->onWorkerStart = function ($task) {
    $socket = stream_socket_client('tcp://xx.xx.xx.xxx:80');
     fwrite($socket, "GET /Mapi/v3/Test/test HTTP/1.1\r\nHost:xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
    $connection = new TcpConnection($socket);
    $connection->onMessage = function($connection, $http_buffer){
        echo $http_buffer;
        $connection->close(); // 连接不用了要记得关闭
    }
    //模拟处理正常其他业务 此处业务耗时大于3秒
    for ($i = 0; $i < 30000; $i++) {
        echo $i . PHP_EOL;
        file_get_contents('workerman.log'); //为了防止此处,一直占用cpu资源,做io操作,让cpu有机会去执行回调函数
    }
};
// 运行worker
Worker::runAll();
  • 暂无评论
小阳光

workerman-json-rpc 的异步客户端就是你这种方式实现的异步。我以前认为AsyncTcpConnection默认就实现了完全异步化。 感谢作者在百忙之中回答。

  • 暂无评论
年代过于久远,无法发表回答
🔝