PHP Socket實現websocket(四)Select函數

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

/*參數列表
int maxfdp是一個整數值,是指集合中全部文件描述符的範圍,即全部文件描述符的最大值加1,不能錯!在Windows中這
個參數的值無所謂,能夠設置不正確。
  
fd_set *readfds是指向fd_set結構的指針,這個集合中應該包括文件描述符,咱們是要監視這些文件描述符的讀變化的,
即咱們關心是否能夠從這些文件中讀取數據了,若是這個集合中有一個文件可讀,select就會返回一個大於0的值,表示有文
件可讀,若是沒有可讀的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返
回負值。能夠傳入NULL值,表示不關心任何文件的讀變化。
  
fd_set *writefds是指向fd_set結構的指針,這個集合中應該包括文件描述符,咱們是要監視這些文件描述符的寫變化的,
即咱們關心是否能夠向這些文件中寫入數據了,若是這個集合中有一個文件可寫,select就會返回一個大於0的值,表示有文
件可寫,若是沒有可寫的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤
返回負值。能夠傳入NULL值,表示不關心任何文件的寫變化。
  
fd_set *errorfds同上面兩個參數的意圖,用來監視文件錯誤異常。
  
struct timeval* timeout是select的超時時間,這個參數相當重要,它能夠使select處於三種狀態:
第一,若將NULL以形參傳入,即不傳入時間結構,就是將select置於阻塞狀態,必定等到監視文件描述符集合中某個文件描
述符發生變化爲止;
第二,若將時間值設爲0秒0毫秒,就變成一個純粹的非阻塞函數,無論文件描述符是否有變化,都馬上返回繼續執行,文件無
變化返回0,有變化返回一個正值;
第三,timeout的值大於0,這就是等待的超時時間,即 select在timeout時間內阻塞,超時時間以內有事件到來就返回了,
不然在超時後無論怎樣必定返回,返回值同上述。
*/

/*
返回值: 

負值:select錯誤

正值:某些文件可讀寫或出錯

0:等待超時,沒有可讀寫或錯誤的文件

PHP的socket_select函數也是調用系統的select函數實現的。PHP中socket_select()函數傳入的read和write數組是引用傳入的,因此每次調用socket_select()後
read和write或者except數組中會包含最新的能夠使用的資源數組。傳入的是要監視的,而調用socket_select後獲得的是能夠用的。
http://php.net/manual/zh/function.socket-select.php

服務器端:
 1 <?php 
 2     $port = 1212;
 3 
 4     $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
 5 
 6     socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
 7 
 8     //綁定全部進入該端口的鏈接
 9     socket_bind($sock, 0, $port);
10 
11     socket_listen($sock);
12 
13     $clients = array($sock);
14 
15     while(true)
16     {
17         //socket_select對讀寫套子節的數字是引用,爲了保證clients不被改變,拷貝一份。
18         $read = $clients;
19         $write = null;
20         $expect = null;
21 
22         //當沒有套字節能夠讀寫繼續等待, 第四個參數爲null爲阻塞, 爲0位非阻塞, 爲 >0 爲等待時間
23         if(socket_select($read, $write, $expect, 0) < 1)
24         {
25             continue;
26         }
27 
28         //查看是否有新的鏈接
29         if(in_array($sock, $read))
30         {
31             $clients[] = $newsock = socket_accept($sock);
32             socket_write($newsock, 'there are '.(count($clients) - 1)." clients connected\r\n");
33             socket_getpeername($newsock, $ip);
34             echo "\nnew client $ip\n";
35             $key = array_search($sock, $read);
36             unset($read[$key]);
37         }
38 
39         //便利全部可讀取數據套子節而後廣播消息
40         foreach ($read as $read_sock)
41         {
42             $data = @socket_read($read_sock, 1024);
43             if($data === false)
44             {
45                 $key = array_search($read_sock, $clients);
46                 socket_getpeername($clients[$key], $ip);
47                 unset($clients[$key]);
48                 echo "client $ip disconnected\n";
49                 continue;
50             }
51             $data = trim($data);
52             if(!empty($data))
53             {
54                 echo $data;
55                 foreach($clients as $send_sock)
56                 {
57                     if($send_sock == $sock || $send_sock == $read_sock)
58                     {
59                         continue;
60                     }
61                     socket_write($send_sock, $data);
62                 }
63             }            
64         }
65     }
66 
67     socket_close($sock);

客戶端:php

 1 <?php 
 2     set_time_limit(0);
 3     $client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
 4     socket_connect($client, '127.0.0.1', 1212);
 5     socket_write($client, "Form Client client.php \r\n");
 6     while(true)
 7     {
 8         $response = socket_read($client, 1024);
 9         echo $response;
10     }
11     socket_close($client);

相關文章
相關標籤/搜索