系统:centos7
php版本:php7.26
使用ev扩展的类需要系统安装libev库,php的ev类是对libev库的封装。libev 是高性能事件循环/事件模型的网络库,提供select,poll,epoll等方法,具体介绍可以参考网上的资料。
经过我调试,使用EvIo类监听IO事件是epoll中的LT即水平触发方式的,所以可以使用阻塞和非阻塞socket。
ev扩展还有很多未知的地方,希望读者提出。
以下示例为一个单进程的服务端示例。
示例代码:
<?php
//创建一个UDP套接字,用于接收UDP数据报
$udp = socket_create(AF_INET,SOCK_DGRAM,SOL_UDP);
if(!$udp){
die('fail!');
}
socket_bind($udp,'127.0.0.1',22001);//UDP无需listen
socket_set_nonblock($udp);//使用非阻塞
//创建一个TCP套接字,用于监听处理客户端连接
$tcp = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if(!$tcp){
die('fail!');
}
socket_bind($tcp,'127.0.0.1',22003);
socket_listen($tcp);
socket_set_nonblock($tcp);//使用非阻塞
$clients = [];
//使用EvIo监听器,监听socket的可读事件,当有连接到来时会触发回调函数
$s1 = new EvIo($tcp,Ev::READ,function ($w)use ($tcp,&$client){
$client = socket_accept($tcp);//建立连接
socket_set_nonblock($client);
$key = uniqid();
$clients[$key] = $client;
//为这个socket连接创建一个监听器,当缓冲区有数据到来时会触发回调函数
$e = new EvIo($client,Ev::READ,function ($w)use ($client,&$clients,$key){
$data = socket_read($client, 1024);
$errno = socket_last_error($client);
socket_clear_error($client);
if(!$data){
//data为false即客户端关闭连接
socket_close($client);
echo $errno,':',socket_strerror($errno);
unset($clients[$key]);
$w->stop();//停止这个监听器
}
var_dump($data);
});
Ev::run();//把这个监听器放进循环队列中
});
//把收到的UDP数据报报文内容发送给客户端
$s2 = new EvIo($udp,Ev::READ,function ($w) use ($udp,&$clients){
$data= socket_read($udp,1024);
if(isset($data{0})) {
foreach ($clients as $item)
socket_send($item, $data,strlen($data),0);
}
var_dump($data);
});
Ev::run();
然后你可以使用telnet命令建立tcp连接,使用nc命令发送UDP数据报,又或者编写一个脚本来测试。
---------------------
https://blog.youkuaiyun.com/qq_33209186/article/details/80919251