系統提供select函數來實現多路複用I/O模型,select系統調用是用來讓咱們的程序監視多個文件句柄的狀態變化的。程序會停在select這裏等待,直到被監視的文件句柄有一個或多個發生了狀態改變。數組
select API:服務器
1)nfds參數指定被監聽的文件描述符的總數。它一般被設置爲select監聽的全部文件描述符中的最大值加1,由於文件描述符是從0開始計數的。
多線程
2)readfds、writefds和exceptfds參數都是輸入輸出型參數,分別指向可讀、可寫和異常等事件對應的文件描述符集合。做爲輸入型參數,應用程序調用select參數時,經過這三個參數傳入本身感興趣的文件描述符。做爲輸出型參數,select調用返回時,內核將修改它們來通知應用程序哪些文件描述符已經就緒。ide
fd_set結構體僅包含一個整型數組,該數組的每一個元素的每一位(bit)標記一個文件描述符。fd_set能容納的文件描述符數量由FD_SETSIZE指定,這就限制了select能同時處理的文件描述符的數量。函數 系統提供了一系列宏來訪問fd_set結構體中的位:性能 |
3)timeout參數用來設置select函數的超時時間。它是一個timeval結構類型的指針,採用指針參數是將它設置爲輸入輸出型參數,內核將修改它以告訴應用程序select等待了多久。
spa
select給咱們提供了一個微秒級的定時方式。若是給timeout變量的tv_sec和tv_usec都傳0,則select將當即返回。若是給timeout傳遞NULL,則select將一直阻塞,直到某個文件描述符就緒。
線程
select成功時返回就緒(可讀、可寫和異常)文件描述符的總數。3d
若是在超時時間內沒有任何文件描述符就緒,select將返回0。指針
select失敗時返回-1並設置errno。若是在select等待期間,程序接收到信號,則select當即返回-1並設置errno爲EINTER。
理解select
select模型的關鍵在於理解fd_set,假如取fd_set爲一字節,fd_set中的每一bit能夠對應一個文件描述符fd,則1字節長的fd_set最大能夠對應8個fd。
(1)執行
fd_set set; FD_ZERO(&set);
則set用位表示是0000 0000。
(2)若fd=5,執行
FD_SET(fd, &set);
後set變爲 0001 0000(第5位設置爲1)。
(3)若再加入fd = 2,fd = 1則set變爲 0001 0011。
(4)執行
select(6, &set, NULL, NULL, NULL);
阻塞等待。
(5)若fd = 1, fd = 2上都發生可讀事件,則select返回,此時set變爲0000 0011。
注意:沒有事件發生的fd = 5被清空。
select模型的特色:
(1)可監控的文件描述符個數取決於sizeof(fd_set)的值,通常爲512或1024。假如服務器上sizeof(fd_set)的值爲512,每一個bit表示一個文件描述符,則服務器上支持的最大文件描述符是512 * 8 = 4096。若是想要調整fd_set的大小,能夠經過編譯內核或其餘方法。
(2)將fd加入select監控的同時,還要再使用一個數組Array保存放到select監控集中的fd,一是用於在select返回後,Array做爲原數據和fd_set進行FD_ISSET判斷。二是select返回後會把之前加入的但並沒有事件發生的fd清空,因此每次開始select前都要從新從Array取得fd逐一加入(FD_ZERO最早),掃描Array的同時取得fd的最大值max_fd,用於select的第一個參數。
(3)select模型必須在select前遍歷Array(加fd,取max_fd),select返回後遍歷Array(FD_ISSET判斷是否有事件發生)。
select的優勢:
select的性能遠遠高於多進程、多線程。
select的缺點:
(1)select監視的文件描述符數量是有限的
(2)每次調用select,都須要把fd集合從用戶態拷貝到內核態,這個開銷在fd不少時會很大,致使服務器性能降低。
(3)每次調用都要在內核遍歷傳遞進來的全部fd,這個開銷在fd不少時也很大。
使用select 的TCP服務器