Skip to content

老陈是一个普通的文艺二逼青年

For The Dream

io复用

Written by chen

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)] );
            }
        }
    }
};
 
 

大致流程见下图:
io复用图

socket · php, socket

Copyright © 2022 老陈是一个普通的文艺二逼青年. 沪ICP备13044041号-1