多路 IO 转接 :select 函数
(1)頭文件:
#include <sys/select.h>(2)函數(shù)原型:
int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout );(3)參數(shù)說明
1)參數(shù)1:監(jiān)聽的所有文件描述符中,最大文件描述符的編號 + 1(即監(jiān)聽 fd 的總個(gè)數(shù))。
2)參數(shù)2、3、4:監(jiān)聽的文件描述符 “是否可讀”、“是否可寫”、“是否異常” 的事件;fd_set代表文件描述符集合,本質(zhì)是位圖。
3)參數(shù)5:設(shè)定超時(shí)返回結(jié)果,若填 NULL 代表永久阻塞,直至有事件發(fā)生, 若值為0代表立即返回,非阻塞效果。
這里有兩點(diǎn)要注意的地方:
1)是最常監(jiān)聽 readfds;writefds 在 epoll 反應(yīng)堆會使用;exceptfds 一般是內(nèi)核給系統(tǒng)函數(shù)內(nèi)部使用。
2)以參 2 readfds 為例,并不是我監(jiān)聽它可讀,它就一定可讀,因此在設(shè)計(jì)上,都是傳入傳出參數(shù)。傳入體現(xiàn)在告訴內(nèi)核,我想監(jiān)聽誰是否可讀。傳出體現(xiàn)在通過 select 函數(shù)的監(jiān)聽,內(nèi)核告訴我具體結(jié)果,誰是可讀的。如下圖
(4)返回值:
成功返回所監(jiān)聽的滿足條件的文件描述符總數(shù)量。
例如:
監(jiān)聽 r:fd1 fd2 fd3
w:fd1 fd3
err:fd1 fd2
滿足條件 r:fd1 fd3
w:fd1 ; err:fd2
則返回值為4 (不要在意 fd1 是否有重復(fù),因?yàn)樗麄儗儆诓煌录?#xff09;。
失敗:返回 -1,設(shè)置 errno (如果 timeout =0, errno = EAGAIN,代表正常)。
(5)添加監(jiān)聽的文件描述符函數(shù):
(6)在返回值中確定哪個(gè)文件描述符可讀,哪個(gè)可寫
fd_set readfds; // 定義監(jiān)聽讀事件的文件描述符集合 FD_ZERO(&readfds); // 清空 FD_SET(fd1, &readfds); FD_SET(fd2, &readfds); FD_SET(fd3, &readfds); // 監(jiān)聽 fd1、fd2、fd3 是否可讀 select(); //以上面結(jié)果為例(不考慮 writefds 和 exceptfds)返回值 = 1,但我不知道是誰 //判斷是否在相應(yīng)集合中 int ret = FD_ISSET(fd1, & readfds); // 發(fā)現(xiàn) ret = 1 說明可讀,意味著客戶端向服務(wù)器發(fā)送數(shù)據(jù),可以通過 fd1 讀取數(shù)據(jù) int ret = FD_ISSET(fd2 & readfds); // 顯然 結(jié)果 = 0 int ret = FD_ISSET(fd3, & readfds); // 顯然 結(jié)果 = 0(7)select 函數(shù)優(yōu)缺點(diǎn)
優(yōu)點(diǎn):一個(gè)線程就可以支持多個(gè)客戶端(多路 IO 都有這個(gè)優(yōu)點(diǎn)),可以跨平臺(select 獨(dú)有)。
缺點(diǎn):
1)同時(shí)監(jiān)聽文件描述符的上限是 1024 個(gè),注意不是因?yàn)榇蜷_文件的上限是 1024(上限數(shù)可以修改),而是因?yàn)樵?select 底層實(shí)現(xiàn)時(shí)候,fd_set使用了宏 FD_SETSIZE = 1024。
2)返回值是一個(gè)數(shù)量,需要循環(huán)遍歷判斷到底誰符合條件,因此高并發(fā)少訪問的時(shí)候,效率低。
3)監(jiān)聽集合和滿足監(jiān)聽條件的集合是同一個(gè)集合,select 后會改變原監(jiān)聽集合,使其無法再次使用,因此,select 前需要將原監(jiān)聽集合保存。
(8)監(jiān)聽事件分類:
需要監(jiān)聽事件分為 2 類,首先一類是建立連接請求(其實(shí)是監(jiān)聽讀事件即服務(wù)器寫給我請求,我來讀),另一類是讀寫事件請求 (這些都是建立連接之后的事)。就是說,最開始需要監(jiān)聽一個(gè)讀描述符,有結(jié)果,意味著有客戶端請求連接,此時(shí)服務(wù)器調(diào)用 accept 函數(shù)便會立即建立連接(雖然 accept 是阻塞函數(shù),但此時(shí)不會有阻塞效果),然后再監(jiān)聽讀寫。
總結(jié)
以上是生活随笔為你收集整理的多路 IO 转接 :select 函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 链路层寻址和ARP
- 下一篇: select 版 高并发服务器