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