五種IO模型
1、阻塞等待:在內(nèi)核將數(shù)據(jù)準備好之前,系統(tǒng)調(diào)用會一直等待。所有的套接字,默認都是阻塞方式。
2、非阻塞等待:如果內(nèi)核沒有將數(shù)據(jù)準備好,系統(tǒng)調(diào)用仍然會返回,并且會返回EWUOLDBLOCK或者EAGAIN錯誤碼。
3、信號驅(qū)動:內(nèi)核將數(shù)據(jù)準備好的時候,使用SIGIO信號通知應(yīng)用程序進行IO操作。
4、多路轉(zhuǎn)接(多路轉(zhuǎn)接):能夠同時等待多個文件句柄的就緒狀態(tài)。
5、異步IO:由內(nèi)核在數(shù)據(jù)拷貝完成時,通知應(yīng)用程序。(而信號驅(qū)動是告訴應(yīng)用程序什么時候可以開始拷貝數(shù)據(jù))。
前四種都屬于同步IO,第五種屬于異步IO。同步IO和異步IO,區(qū)別在于同步IO會參與IO結(jié)果的獲取的過程。而異步IO則是不會參與IO結(jié)果獲取的過程,直接拿到最終的IO結(jié)果。
IO的本質(zhì)就是等和拷貝數(shù)據(jù)。也就是說沒有數(shù)據(jù)的時候,就需要等待數(shù)據(jù),當有數(shù)據(jù)的時候,再將數(shù)據(jù)拷貝走。而高效的IO,要達到高效,關(guān)鍵在于減少等的比重才能達到效果。在上述的五種IO模型中,多路轉(zhuǎn)接的方式,一次等待多個文件描述符,在某種意義上等的效率更高,也就是說一次等通知多個就緒能夠進行拷貝的文件描述符。
I/O多路轉(zhuǎn)接之select
select系統(tǒng)調(diào)用是用來讓我們的程序監(jiān)視多個文件描述符的狀態(tài)變化的; 程序會停在select這里等待,直到被監(jiān)視的文件描述符有一個或多個發(fā)生了狀態(tài)改變;
函數(shù)原型
參數(shù)解釋:
nfds表示最大文件描述符+1。
readfds、writefds、exceptfds(位圖結(jié)構(gòu))分別需要檢測的可讀文件描述符集合、可寫文件描述符集合和異常文件描述符集合。
timeout表示設(shè)置select()的等待時間。(timeout取值(NULL、0、特定時間)
NULL表示阻塞等待,
0則表示僅檢測描述符集合的狀態(tài),然后立即返回,
特定時間值表示select的等待時間)。
操作fd_set位圖結(jié)構(gòu)的接口
函數(shù)返回值
執(zhí)行成功---->則返回文件描述符狀態(tài)已改變的個數(shù)
如果返回0---->代表在描述詞狀態(tài)改變前已超過timeout時間,沒有返回
當有錯誤發(fā)生時則---->返回-1,錯誤原因存于errno,此時參數(shù)readfds,writefds, exceptfds和timeout的 值變成不可預(yù)測。
select特點
可監(jiān)控的文件描述符個數(shù)取決與sizeof(fd_set)的值. 我這邊服務(wù)器上sizeof(fd_set)=512,每bit表示一個文件描述符,則我服務(wù)器上支持的最大文件描述符是512*8=4096。
將fd加入select監(jiān)控集的同時,還要再使用一個數(shù)據(jù)結(jié)構(gòu)array保存放到select監(jiān)控集中的fd。? ? ? ? ?一是用于再select 返回后,array作為源數(shù)據(jù)和fd_set進行FD_ISSET判斷。
???????二是select返回后會把以前加入的但并無事件發(fā)生的fd清空,則每次開始select前都要重新從array取得fd逐一加入(FD_ZERO最先),掃描array的同時取得fd最大值maxfd,用于select的第一個參數(shù)。
select缺點
每次調(diào)用select, 都需要手動設(shè)置fd集合, 從接口使用角度來說也非常不便.
每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),這個開銷在fd很多時會很大
每次調(diào)用select都需要在內(nèi)核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大
select支持的文件描述符數(shù)量太小
I/O多路轉(zhuǎn)接之poll
函數(shù)原型
參數(shù)解釋:
fds是一個poll函數(shù)監(jiān)聽的結(jié)構(gòu)列表. 每一個元素中, 包含了三部分內(nèi)容: 文件描述符, 監(jiān)聽的事件集合, 返回的事件集合.
其中events和revents的取值可以為如下。比如POLLIN或者POLLOUT但是某一位為1的宏,可以設(shè)置進events或者內(nèi)核設(shè)置進revents中。
nfds表示fds數(shù)組的長度
timeout表示poll函數(shù)的超時時間, 單位是毫秒(ms).
返回值
返回值? <? 0, 表示出錯;
返回值? =? 0, 表示poll函數(shù)等待超時;
返回值? >? 0, 表示poll由于監(jiān)聽的文件描述符就緒而返回
poll的優(yōu)點
不同與select使用三個位圖來表示三個fdset的方式,poll使用一個pollfd的指針實現(xiàn)
????????pollfd結(jié)構(gòu)包含了要監(jiān)視的event和發(fā)生的event,不再使用select“參數(shù)-值”傳遞的方式. 接口使用比 select更方便
????????poll并沒有最大數(shù)量限制 (但是數(shù)量過大后性能也是會下降,因為需要輪詢的檢測就緒的事件).
poll的缺點
在監(jiān)聽的文件句柄增多時
和select函數(shù)一樣,poll返回后,需要輪詢pollfd來獲取就緒的描述符.
每次調(diào)用poll都需要把大量的pollfd結(jié)構(gòu)從用戶態(tài)拷貝到內(nèi)核中.
同時連接的大量客戶端在一時刻可能只有很少的處于就緒狀態(tài), 因此隨著監(jiān)視的描述符數(shù)量的增長, 其效率也會線性下降.
I/O多路轉(zhuǎn)接之epoll
函數(shù)原型
創(chuàng)建epoll句柄
epoll的函數(shù)與select和poll的函數(shù)不同,epoll的函數(shù)有三個分別獨立完成各自功能。
參數(shù)size表示所創(chuàng)建的epoll模型,最大能監(jiān)聽文件句柄的數(shù)目。
返回值
success -----> return 正數(shù)。fail -----> return -1
將要監(jiān)控的文件描述符進行注冊
參數(shù):
? ? ? ? epfd表示我們所創(chuàng)建的epoll模型的文件句柄。
? ? ? ? op表示關(guān)心添加的文件句柄的什么行為。用三個宏來表示。
????????????????EPOLL_CTL_ADD :注冊新的fd到epfd中;
????????????????EPOLL_CTL_MOD :修改已經(jīng)注冊的fd的監(jiān)聽事件;
????????????????EPOLL_CTL_DEL :從epfd中刪除一個fd;
? ? ? ? fd表示我們需要添加關(guān)心的文件句柄
? ? ? ? event表示我們關(guān)心添加的文件句柄的什么事件。epoll_event結(jié)構(gòu)體如下:
????????????????
? ? ? ? ? ? ? ? 其中events可以是一下宏的集合
返回值:
success -----> return 0。fail -----> return -1
等待文件描述符就緒
參數(shù):
????????epfd表示我們所創(chuàng)建的epoll模型的文件句柄。
? ? ? ? events表示系統(tǒng)監(jiān)聽到文件句柄的事件就緒并拷貝至用戶的結(jié)構(gòu)體數(shù)組
? ? ? ? maxevents表示events數(shù)組的大小。
? ? ? ? timeout表示超時時間(毫秒,0會立即返回,-1是永久阻塞)。
返回值:
? ? ? ? success ----> return 就緒的文件描述符的個數(shù)。
? ? ? ? 超時? ----->? return 0
? ? ? ? fail? ----> return -1
多路轉(zhuǎn)接的工作原理
首先,epoll的使用是一個單進程,因此我們可以通過進程找到對應(yīng)的epoll句柄。
select和poll的原理:忽略其中的1、2和文件句柄,就單單看3。當外設(shè)將數(shù)據(jù)通過驅(qū)動刷新到對應(yīng)文件句柄中,該文件句柄就就緒了。但是使用者需要輪詢遍歷3這個隊列。
epoll的原理:現(xiàn)在我們需要將上圖看作一個整體,epoll模型中存在一個紅黑樹存放關(guān)心的文件句柄,并帶有回調(diào)函數(shù)。當外設(shè)將數(shù)據(jù)通過驅(qū)動刷新到對應(yīng)文件句柄中,該文件句柄就就緒了。然后調(diào)用其回調(diào)函數(shù),將3中就緒的文件句柄添加到2中的就緒隊列中。也就是說,epoll不用再輪詢遍歷3這個隊列了,直接遍歷2這個就緒隊列就能拿到所有就緒的文件句柄了。
? ? ? ? 其次,epoll中維護著紅黑樹、就緒隊列等數(shù)據(jù)結(jié)構(gòu),在Linux中都是交由文件管理的。著就是為什么要創(chuàng)建epoll模型,也就是epoll文件句柄了。文章來源:http://www.zghlxwxcb.cn/news/detail-703012.html
? ? ? ? epoll中的三個函數(shù)epoll_create、epoll_ctl、epoll_wait,epoll_create函數(shù)負責創(chuàng)建句柄,并初始化隊列3的大小。epoll_ctl函數(shù)負責向紅黑樹中添加關(guān)心的文件句柄,并注冊回調(diào)函數(shù)。epoll_wait函數(shù)則是遍歷就緒隊列2,拿到就緒的文件句柄。文章來源地址http://www.zghlxwxcb.cn/news/detail-703012.html
到了這里,關(guān)于服務(wù)器(I/O)之多路轉(zhuǎn)接的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!