I/O複用之Select模型
編程
I/O複用使得程序可以同時監聽多個文件描述符,可是,他自己也是阻塞的,而且當一個或多個文件描述符準備就緒時,若是不採用其餘措施,程序只能按順序處理其中的每一個文件描述符。若是要使程序可以並行運行,只能使用多進程或多線程的方式。數組
Linux下實現I/O複用的系統調用主要有select、poll和epoll,下面將詳細介紹select的系統調用。服務器
Select系統調用的用途:在一段時間內,監聽用戶感興趣的文件描述符上面的可讀、可寫和異常等事件。數據結構
相關API的介紹:多線程
#include <sys/select.h> int select(int nfds, fd_set * readfds, fd_set * writefdds, fd_set * exceptfds, struct timeval * timeout);
①、nfds參數:全部監聽的文件描述符的最大值 + 1socket
②、readfds、writefds和exceptfds參數分別爲可讀、可寫和異常等事件對應的文件描述符集合;程序只須要傳入本身感興趣的文件描述符,內核將修改他們來通知程序那些文件描述符已經準備就緒;fd_set結構體僅包含一個整形數組,該數組的每個元素的每一位標誌一個文件描述符,下面的一組宏用來操做fd_set的每一位:測試
FD_ZERO(fd_set * fdset);//清除fd_set的全部位 FD_SET(int fd, fd_set * fdset);//設置fdset的位fd FD_CLR(int fd, fd_set * fdset);//清除fdset的位fd int FD_ISSET(int fd, fd_set * fdset);//測試fdset的位fd是否被設置
③、ttimeout參數:timeout參數是一個timeval結構體,timeval的結構體的定義以下:spa
struct timeval { long tv_sec;//秒數 long tv_usec;//微秒數 };
若是tv_sec和tv_usec都設置爲0,則select當即返回, 若是timeout參數設置爲NULL,則select一直阻塞直到某個文件描述符準備就緒。.net
返回值:成功返回就緒的文件描述符的總數,若是超過期間內沒有任何文件描述符準備就緒,select將返回0,失敗則返回-1並設置errno;若在select等待事件內程序接收到信號,則select當即返回-1,並設置errno爲EINTER。線程
文件描述符的就緒條件:
可讀描述符就緒條件:
①、接收緩衝區中的字節數大於或等於SO_RCVLOWAT標誌
‚、有新的鏈接請求
ƒ、對方關閉鏈接
④、有未處理的錯誤
可寫描述符的就緒條件:
①、發送緩衝區中的可用字節數大於或等於SO_SENLOWAT標誌
‚、寫操做被關閉
ƒ、有未處理的錯誤
異常文件描述符的就緒條件:
①、socket上接收帶外數據
代碼示例:
http://www.oschina.net/code/snippet_861360_27324
分享的代碼主要是使用select系統調用和多線程編程實現一個簡單的並行的TCP服務器
select 模型的有缺點:
優勢:select模型的優勢之一就是良好的跨平臺支持
缺點:
1、單個進程可以監測的文件描述符有限,通常爲1024,能夠經過修改內核修改
2、select維護了存儲大量文件描述符的數據結構,隨着文件描述符的增長,其複製的開銷及遍歷形成的開銷影響系統效率。