系统:centos7
php版本:php7.26
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数据报,又或者编写一个脚本来测试。