php之socket笔记

By | 2014/11/15

随着开发深入,socket的应用还是比较常见的。毕竟自己是业余出身,水平到不了自己开发php扩展的程度。所以利用php本身的功能,实现socket的一些应用还算是比较靠谱的选择。

如果在linux平台,可以考虑Swoole扩展,功能还是很强大的。至于windows,扩展的编译实在不方便。还是进入我们的主角吧,php的socket编程。内容多是基于众多网上资料拼凑而成。

一.需要了解的基本概念
1.阻塞/非阻塞 阻塞IO是指调用结果返回之前,当前线程会被挂起;相反,非阻塞指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
2.多路复用 对于 Socket 来说,应该说能同时处理多个连接的模型都应该被称为多路复用,目前比较常用的有 select/poll/epoll/kqueue。在这些多路复用的模式中,异步阻塞/非阻塞模式的扩展性和性能最好。
3.同步/异步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回;相反,当一个异步过程调用发出后,调用者不能立刻得到结果,实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

使用 select/poll 的同步模型:属于同步非阻塞 IO 模型,代码如下:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/** 
 * SelectSocketServer Class 
 * By James.Huang <shagoo#gmail.com> 
**/  
set_time_limit(0);  
class SelectSocketServer   
{  
    private static $socket;  
    private static $timeout = 60;  
    private static $maxconns = 1024;  
    private static $connections = array();  
    function SelectSocketServer($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();                              // 选择一个连接,获取读、写连接通道               if (socket_select($readfds, $writefds, $e = null, $t = self::$timeout))                {                   // 如果是当前服务端的监听连接                   if (in_array($socket, $readfds)) {                       // 接受客户端连接                       $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";  
                    }  
                }  
 
                // 轮循写通道  
                foreach ($writefds as $wfd) {  
                    $i = (int) $wfd;  
                    $w = 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(2000);

2 thoughts on “php之socket笔记

  1. f

    Bosch lui a conseillé d’utiliser seulement à mi-parcours de l’urine pour le dépistage des drogues MLB.

    Reply
  2. t

    Nous voulons simplement faire cette lutte se produire, pour l’amour des fans, pour le bien de millions de personnes dans le monde qui sont impatients de voir ce combat, \u0026 rdquo; -PacquiaoFollow Damon Salvadore sur TwitterFOR PLUS NOUVELLES ET MISES à JOUR SPORTS, cliquez sur ce lien pour visiter LATIN POST.

    Reply

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据