参考文献

5种IO模型:https://blog.mailjob.net/posts/3565199751.html

github代码下载:https://github.com/mailjobblog/dev_php_io/tree/master/test/signal

快速了解信号驱动io:https://www.itzhai.com/articles/it-seems-not-so-perfect-signal-driven-io.html

Linux 信号列表:https://wiki.swoole.com/#/other/signal

安装信号处理器函数(pcntl_signal):https://www.php.net/manual/zh/function.pcntl-signal.php

向进程发送信号函数(posix_kill):https://www.php.net/manual/zh/function.posix-kill.php

调用等待信号的处理器函数(pcntl_signal_dispatch):https://www.php.net/manual/zh/function.pcntl-signal-dispatch.php

获取进程的 PID 函数(posix_getpid):https://www.php.net/manual/zh/function.posix-getpid.php

信号驱动IO原理

所谓信号驱动式I/O(signal-driven I/O),就是预先告知内核,当某个描述符准备发生某件事情的时候,让内核发送一个信号通知应用进程。

主要的实现:

  • Berkeley的实现使用SIGIO信号支持套接字和终端设备上的信号驱动式I/O;
  • SVR4使用SIGPOLL信号支持流设备上的信号驱动。

SIGPOLL等价于SIGIO。

通过UDP的recvfrom()函数演示其工作原理如下图所示:

image-20201101160607451

系统注册了ISGIO信号处理函数,并且启动了信号驱动式IO后,就可以继续执行程序了,等到数据报准备好之后,内核会发送一个SIGIO信号给应用进程,然后应用进程在信号处理函数中调用recvfrom读取数据报。

这种模型在内核等待数据报达到期间进程不会被阻塞,可以继续执行。

代码示例

server.php

<?php
require_once __DIR__."/../../vendor/autoload.php";

use DevPhpIO\Signal\Worker;

$server = new Worker('0.0.0.0', 9500);
$server->on('connect', function($server, $client){
    dd($client, "客户端成功建立连接");
});

$server->on('receive', function(Worker $server, $client, $data){
    dd($data, "处理client的数据");
    $server->send($client, "hello i’m is server");
    // $server->close($client);
}); 

$server->on('close', function($server, $client){
    dd($client, "连接断开");
});

$server->start();

client.php

<?php
require_once __DIR__."/../../vendor/autoload.php";

// 连接服务端
$fp = stream_socket_client("tcp://127.0.0.1:9500");
fwrite($fp, "hello world lalala");
dd(fread($fp, 65535));

演示截图

image-20210507222339142