1、基本概念
多路复用模型是对多个IO操作进行检测,返回可操作集合,这样就可以对其进行操作了。这样就避免了阻塞IO不能随时处理各个IO和非阻塞占用系统资源的确定。多路复用适用如下场合:
1. 当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
2. 当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
3. 如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
4. 如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
5. 如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
2、socket_select
1 2 |
int socket_select ( array &$read , array &$write , array &$except , int $tv_sec [, int $tv_usec = 0 ] ) |
socket_select()
等待sockets
打开的连接事件。socket_select()
调用系统的select(2)
函数来工作:前面三个参数是你要使用的socket
的数组;你可以对其读取,写入和获取异常(分别针对三个参数)。
3、 php实现多路复用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php $protocol = getprotobyname( 'tcp' ); ( $master = socket_create( AF_INET, SOCK_STREAM, $protocol ) ) or die( 'socket create error' ); socket_bind( $master, '0.0.0.0', 8000 ) or die( 'socket bind error' ); socket_listen( $master ); $sockets = [ $master ]; while( true ) { $read = $sockets; $write = null; $except = null; if( false === socket_select( $read, $write, $except, null ) ) { die( 'socket select error' ); } foreach( $read as $i => $socket ) { if( $read[$i] === $master ) { $conn = socket_accept( $read[$i] ); $sockets[] = $conn; } else { $data = ''; while( $tmp_read = socket_read( $read[$i], 2048 ) ) { $data .= $tmp_read; if( substr( $tmp_read, -1 ) == "\n" ) { break; } } if( 0 === strlen( $data ) ) { $key_to_del = array_search($read[$i], $sockets, TRUE); socket_close($read[$i]); unset($sockets[$key_to_del]); } else if( $data === false ) { $key_to_del = array_search($read[$i], $sockets, TRUE); unset($sockets[$key_to_del]); } else { $msg = "HTTP/1.1 200\r\n" ."Content-type:textml;charset=utf-8\r\n" ."Content-length:".strlen($data)."\r\n" ."Connection:close\r\n" ."\r\n" .$data."\r\n\r\n"; socket_write($read[$i], $data ); socket_close($read[$i]); unset( $sockets[array_search($read[$i], $sockets, TRUE)] ); } } } }; |