宁泽林_NiZerin - 互联网技术博客

  • PHP
  • Go
  • Java
  • Rust
  • Python
  • 交流群
  • 关于我
  • 留言版
  1. 首页
  2. linux
  3. 正文

玩转 PHP 网络编程全套之 I/O 复用

2020年6月3日 1085点热度 0人点赞 0条评论
PHP的socket扩展提供了一个多路I/O事件复用select

IO复用

I/O复用函数本身也是阻塞I/O,发起系统调用同样的要被挂起,直到就绪事件发生,才会运行。所以也称为同步I/O模型。
I/O复用函数一般用的有select,epoll,poll,kqueue,devpoll等PHP只提供了一个select。

同步I/O模型与异步I/O模型

同步IO模型是向应用程序通知的是I/O就绪事件,而异步I/O模型则是向应用程序通知的是完成事件,后续我们在编写代码过程会进行模拟异步I/O的实现。

测试源码

$ip = "0.0.0.0";
$port = $argv[1];
$sockefd = socket_create(AF_INET,SOCK_STREAM,0);
socket_set_option($sockefd,SOL_SOCKET,SO_REUSEPORT,1);
socket_bind($sockefd,$ip,$port);
socket_listen($sockefd,5);
$connectionfds = [];
$readfds = [$sockefd];
$writefds = [$sockefd];
$exceptionfds = [$sockefd];
$bufferMessage = "hello,world";
$recvMessage = "";
$remoteIP;
$remoteAddr;
fprintf(STDOUT,"server pid=%d\n",posix_getpid());
$i=0;
while ("server") {
        $read_fds      = $readfds;
        $write_fds     = $writefds;
        $exception_fds = $exceptionfds;
        $connectNum = socket_select($read_fds, $write_fds, $exception_fds, NULL);
        if (!$connectNum) {
            break;
        }
        foreach ($read_fds as $fd) {
            if ($fd == $sockefd) {
                $connfd = socket_accept($sockefd);
                socket_set_nonblock($connfd);
                socket_getpeername($connfd,$remoteIP,$remoteAddr);
                fprintf(STDOUT, "new connection %s ,ip is %s,port is %d\n", $connfd,$remoteIP,$remoteAddr);
                $readfds[]       = $connfd;
                $exceptionfds[]  = $connfd;
                $connectionfds[] = $connfd;
            } else {
                $recvMessage = socket_read($fd, 8192);
                unset($readfds[array_search($fd, $readfds)]);
                if (strcasecmp("QUIT",$recvMessage)){
                    socket_send($fd,"quit\n",6,0);
                    socket_close($fd);
                    unset($exceptionfds[array_search($fd, $exceptionfds)]);
                    unset($writefds[array_search($fd, $writefds)]);
                }
                if (!$recvMessage) {
                    socket_close($fd);
                    unset($exceptionfds[array_search($fd, $exceptionfds)]);
                    unset($writefds[array_search($fd, $writefds)]);
                } else {
                    fprintf(STDOUT, "recv from client msg:%s\n", $recvMessage);
                    array_push($writefds, $fd);
                }
            }
        }
        foreach ($write_fds as $fd) {
            $writeBytes = socket_write($fd, $bufferMessage, strlen($bufferMessage));
            unset($writefds[array_search($fd, $writefds)]);
            if (!$writeBytes) {
                socket_close($fd);
                unset($readfds[array_search($fd, $readfds)]);
                unset($exceptionfds[array_search($fd, $exceptionfds)]);
            } else {
                array_push($readfds, $fd);
            }
        }
        foreach ($exception_fds as $fd) {
            socket_close($fd);
            unset($readfds[array_search($fd, $readfds)]);
            unset($exceptionfds[array_search($fd, $exceptionfds)]);
            unset($writefds[array_search($fd, $writefds)]);
        }
}
socket_close($sockefd);

启动服务

然后阻塞在selectI/O函数
玩转 PHP 网络编程全套之 I/O 复用
玩转 PHP 网络编程全套之 I/O 复用
玩转 PHP 网络编程全套之 I/O 复用
玩转 PHP 网络编程全套之 I/O 复用
第二个客户端连接时
玩转 PHP 网络编程全套之 I/O 复用
玩转 PHP 网络编程全套之 I/O 复用

总结

select的基本功能:就是为了能监听多个客户端的连接,它本身还是并没有特别的地方,但是它也是有缺点的,就是每次都得传递文件描述符集合给它,同时返回的就绪文件也要自己遍历,如果监听太多,性能也不怎么样,更关键的是它最多只能监听1024个文件描述符,毕竟它在内核中是以位形式存储。
原理图:【实在找不到吊炸天的画图软件了】
该原理图请配合select函数亲自测试并调试
玩转 PHP 网络编程全套之 I/O 复用

  • H2
  • H3
  • |
  • |
  • |
本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: linux php
最后更新:2020年6月3日

NiZerin

博主已经躺平了,后面很少会更新博客。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

分类
  • Angular
  • CSS3
  • docker
  • Flutter
  • git
  • Go
  • H5
  • Java
  • JavaScript
  • Laravel
  • linux
  • Node.js
  • PHP
  • Python
  • React
  • redis
  • Vue.js
  • windows
  • WordPress
  • 交流
  • 小程序
  • 工具
  • 网站公告
标签聚合
vue laravel wordpress flutter go javascript translations php
友情链接
  • PHP函数字典
  • 宝塔运维特惠
  • 科学上网
  • 阿里云特惠

COPYRIGHT © 2021 nizer.in. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang