php socket select IO复用
来源:互联网 发布:苏亚雷斯实况巅峰数据 编辑:程序博客网 时间:2024/06/15 05:58
此篇博客是接着上篇php socekt阻塞模型PHP代码(php socket IO阻塞方式的Server/Client)的进阶,IO阻塞模型只能是同一个时刻只能由一个客户端进行访问,除非利用多进程或多线程才能达到多个用户并发访问的,因涉及到多进程和多线程,暂时跳过,
此片为linux的IO操作的5大模型第三种模型:IO复用,而IO复用又有多种方式实现,常见的如select、poll、epoll函数。这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这些函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数,这些定义网上资料都很多,我这就不一一描述,如有需要可参考:socket阻塞与非阻塞,同步与异步
下面是socket IO复用 select 模型代码PHP 的代码描述,讲述如何使用PHP代码实现select模型。其中也对socket_select的作用,进行自我总结
select_server.php
<?php/** * server.php. * User: lvfk * Date: 2017/12/1 0001 * Time: 16:47 * Desc: */set_time_limit(0);class SelectSocketServer{ private static $socket; private static $timeout = 60; private static $maxconns = 1024; private static $connections = array(); function __construct($port) { global $errno, $errstr; if ($port < 1024) { die("Port must be a number which bigger than 1024\n"); } $socket = socket_create_listen($port); if (!$socket) die("Listen $port failed"); socket_set_nonblock($socket); // 非阻塞 while (true) { $readfds = array_merge(self::$connections, array($socket)); $writefds = array(); // 选择一个连接,获取读、写连接通道 $e = NULL; /* * socket_select是阻塞,有数据请求才处理,否则一直阻塞 * 此处$readfds会读取到当前活动的连接 * 比如执行socket_select前的数据如下(描述socket的资源ID): * $socket = Resource id #4 * $readfds = Array * ( * [0] => Resource id #5 //客户端1 * [1] => Resource id #4 //server绑定的端口的socket资源 * ) * 调用socket_select之后,此时有两种情况: * 情况一:如果是新客户端2连接,那么 $readfds = array([1] => Resource id #4),此时用于接收新客户端2连接 * 情况二:如果是客户端1(Resource id #5)发送消息,那么$readfds = array([1] => Resource id #5),用户接收客户端1的数据 * * 通过以上的描述可以看出,socket_select有两个作用,这也是实现了IO复用 * 1、新客户端来了,通过 Resource id #4 介绍新连接,如情况一 * 2、已有连接发送数据,那么实时切换到当前连接,接收数据,如情况二 */ if (socket_select($readfds, $writefds, $e, self::$timeout)) { // 如果是当前服务端的监听连接 if (in_array($socket, $readfds)) { echo "socket_accept\n"; // 接受客户端连接 $newconn = socket_accept($socket); $i = (int) $newconn; $reject = ''; if (count(self::$connections) >= self::$maxconns) { $reject = "Server full, Try again later.\n"; } // 将当前客户端连接放入 socket_select 选择 self::$connections[$i] = $newconn; // 输入的连接资源缓存容器 $writefds[$i] = $newconn; // 连接不正常 if ($reject) { socket_write($writefds[$i], $reject); unset($writefds[$i]); self::close($i); } else { echo "Client $i come.\n"; } // remove the listening socket from the clients-with-data array $key = array_search($socket, $readfds); unset($readfds[$key]); } // 轮循读通道 foreach ($readfds as $rfd) { // 客户端连接 $i = (int) $rfd; // 从通道读取 $line = @socket_read($rfd, 2048, PHP_NORMAL_READ); if ($line === false) { // 读取不到内容,结束连接 echo "Connection closed on socket $i.\n"; self::close($i); continue; } $tmp = substr($line, -1); if ($tmp != "\r" && $tmp != "\n") { // 等待更多数据 continue; } // 处理逻辑 $line = trim($line); if ($line == "quit") { echo "Client $i quit.\n"; self::close($i); break; } if ($line) { echo "Client $i >>" . $line . "\n"; //发送客户端 socket_write($rfd, "$i=>$line\n"); } } // 轮循写通道 foreach ($writefds as $wfd) { $i = (int) $wfd; socket_write($wfd, "Welcome Client $i!\n"); } } } } function close ($i) { socket_shutdown(self::$connections[$i]); socket_close(self::$connections[$i]); unset(self::$connections[$i]); }}new SelectSocketServer(3000);
select_client.php
<?php/** * client.php. * User: lvfk * Date: 2017/12/1 0001 * Time: 17:05 * Desc: */function debug ($msg){ error_log($msg, 3, '/tmp/socket.log');}if ($argv[1]) { $socket_client = stream_socket_client('tcp://127.0.0.1:3000', $errno, $errstr, 30);//stream_set_timeout($socket_client, 0, 100000); if (!$socket_client) { die("$errstr ($errno)"); } else { $msg = trim($argv[1]); for ($i = 0; $i < 5; $i++) { $res = fwrite($socket_client, "$msg($i)\n"); usleep(100000);debug(fread($socket_client, 1024)); // 将产生死锁,因为 fread 在阻塞模式下未读到数据时将等待 } fwrite($socket_client, "quit\n"); // add end token debug(fread($socket_client, 1024)); fclose($socket_client); }}else { $phArr = array(); for ($i = 0; $i < 5; $i++) { $phArr[$i] = popen("php ".__FILE__." '{$i}:test'", 'r'); } foreach ($phArr as $ph) { pclose($ph); }}
阅读全文
0 0
- php socket select IO复用
- io复用select pselect
- IO复用 select Demo
- IO复用:select函数
- IO复用:select函数
- IO复用select模型
- select多路IO复用
- IO复用 socket epoll
- php/socket.io实现扫码登录
- IO服用实现linux socket聊天程序(select)
- linux下socket编程IO多路复用select模型
- select,poll,epoll 三种socket IO模型
- select,epoll 多路IO复用
- linux编程---IO复用---select
- 基于socket.io的php扩展介绍---phpsocket.io
- socket select
- Socket Select
- Socket & Select
- 生成对抗网络学习
- 新手村 过程函数与递归 数的计算
- mount 保证挂载成功
- 由java的extend的优劣引发的讨论技巧
- bzoj1597 土地购买【斜率优化dp】
- php socket select IO复用
- Robot Framework
- [ARC085]E
- ABAP Debug SU01D to get SAP_ALL
- 返回成功判断的 几种状态
- shell在进行字符串截取的过程中,报的错bad substitution 解决办法
- php 解决 约瑟夫环
- 说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
- 使用PropTypes进行类型检测