系統提供select函數來實現多路複用輸入/輸出模型。
傳向select的參數告訴內核:
1)我們所關心的文件描述符。
2)對每個描述符,我們所關心的狀態。(我們是要想從一個文件描述符中讀或者寫,還是關注一個描述符中是否出現異常)
3)我們要等待多長時間。(我們可以等待無限長的時間,等待固定的一段時間,或者根本就不等待)
從 select函數返回後,內核告訴我們以下信息:
1)已經做好準備的描述符的個數。
2)對於三種條件哪些描述符已經做好準備。(讀,寫,異常)
使用這些返回信息,就可調用相應的I/O函數(read/write或recv/send)
以阻塞方式監聽讀事件:
從代碼中可以看到,我們定義了一個fds數組,裏面存放了我們所關心的文件描述符。
數組的第一個元素是listen_sock,一旦監聽套接字準備好了,就accept,再將返回的文件描述符添加到fds中;
數組的其它元素是普通的socket(就是accept返回的文件描述符),如果select監聽到有普通socket準備好了,就說明有數據發過來了,就read。
需要注意的的是:
1)select的第一個參數是當前最大的文件描述符+1(其實就是select要檢查的文件描述符的數目,它的下標是從0開始的),所以,添加了文件描述符之後,記得要更新。
2)有client退出後,select就不需要再監聽它了,記得關閉文件描述符,並修改fds中的值。
代碼測試:
-------------------------------------------------------------------------------------------------------------------------------------------
使用select的優缺點:
優點:(1)相較於之前多線程的方法,使用select不用創建線程,更方便
(2)select目前幾乎在所有的平臺上都支持,其良好跨平臺支持也是它的一個優點
缺點:(1)能夠監視的文件描述符的數量存在最大限制,在Linux上一般爲1024,因爲它依賴於文件系統
(2)select()所維護的文件描述符的數據結構,隨着文件描述符數量的增大,其複製的開銷也線性增長。
(3)由於網絡響應時間的延遲使得大量TCP連接處於非活躍狀態,但調用select()會對所有socket進行一次線性掃描,這也會有一些開銷