网络IO模型
IO有兩種操作,同步IO和異步IO。同步IO指的是,必須等待IO操作完成后,控制權(quán)才返回給用戶(hù)進(jìn)程。異步IO指的是,無(wú)須等待IO操作完成,就將控制權(quán)返回給用戶(hù)進(jìn)程。
網(wǎng)絡(luò)中的IO,由于不同的IO設(shè)備有著不同的特點(diǎn),網(wǎng)絡(luò)通信中往往需要等待。常見(jiàn)的有以下4種情況。
(1)輸入操作:等待數(shù)據(jù)到達(dá)套接字接收緩沖區(qū)。
(2)輸出操作:等待套接字發(fā)送緩沖區(qū)有足夠的空間容納將要發(fā)送的數(shù)據(jù)。
(3)服務(wù)器接收連接請(qǐng)求:等待新的客戶(hù)端連接請(qǐng)求的到來(lái)。
(4)客戶(hù)端發(fā)送連接請(qǐng)求:等待服務(wù)器會(huì)送你個(gè)客戶(hù)的發(fā)起的SYN所對(duì)應(yīng)的ACK。
當(dāng)一個(gè)網(wǎng)絡(luò)IO(假設(shè)是read)發(fā)生時(shí),它會(huì)涉及兩個(gè)系統(tǒng)對(duì)象,一個(gè)是調(diào)用這個(gè)IO的進(jìn)程,另一個(gè)是系統(tǒng)內(nèi)核。當(dāng)一個(gè)read操作發(fā)生時(shí),它會(huì)經(jīng)歷兩個(gè)階段:(1)等待數(shù)據(jù)準(zhǔn)備;(2)將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中。
?
4種網(wǎng)絡(luò)IO模型
(1)阻塞IO模型(2)非阻塞IO模型(3)多路IO復(fù)用模型(4)異步IO模型
?
1.阻塞IO模型
在Linux中,默認(rèn)情況下所有的socket都是阻塞的,一個(gè)典型的讀寫(xiě)流程如下圖:
阻塞和非阻塞的概念描述的是用戶(hù)線程調(diào)用內(nèi)核IO操作的方式:阻塞是指IO操作需要徹底完成后才返回用戶(hù)空間;而非阻塞是指IO操作被調(diào)用后立即返回給用戶(hù)一個(gè)狀態(tài)值,不需要等到IO操作徹底完成。
?
?2.非阻塞IO模型
在Linux下,可以通過(guò)設(shè)置socket使IO變?yōu)榉亲枞麪顟B(tài)。當(dāng)對(duì)一個(gè)非阻塞的socket執(zhí)行read操作時(shí),流程如下圖
?
?
3.多路IO復(fù)用模型
多路IO復(fù)用,有時(shí)也稱(chēng)為事件驅(qū)動(dòng)IO。它的基本原理就是有個(gè)函數(shù)(如select)會(huì)不斷地輪詢(xún)所負(fù)責(zé)的socket,當(dāng)某個(gè)socket有數(shù)據(jù)到達(dá)了,就通知用戶(hù)進(jìn)程,多路IO復(fù)用模型的流程圖如下:
?
?
select、poll和epoll的區(qū)別
select、poll和epoll都是多路IO復(fù)用的機(jī)制。多路IO復(fù)用就通過(guò)一種機(jī)制,可以監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒(一般是讀就緒或者寫(xiě)就緒),能夠通知程序進(jìn)行相應(yīng)的讀寫(xiě)操作。但select、poll和epoll本質(zhì)上都是同步IO,因?yàn)樗鼈兌夹枰谧x寫(xiě)事件就緒后自己負(fù)責(zé)進(jìn)行讀寫(xiě),即是阻塞的,而異步IO則無(wú)須自己負(fù)責(zé)進(jìn)行讀寫(xiě),異步I/O的實(shí)現(xiàn)會(huì)負(fù)責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶(hù)空間。
下面對(duì)這3種多路IO復(fù)用進(jìn)行對(duì)比。
(1) 首先還是來(lái)看常見(jiàn)的select()和poll()。對(duì)于網(wǎng)絡(luò)編程來(lái)說(shuō),一般認(rèn)為poll比select要高級(jí)一些,這主要源于以下幾個(gè)原因。
1)poll()不要求開(kāi)發(fā)者在計(jì)算最大文件描述符時(shí)進(jìn)行+1的操作。
2)poll()在應(yīng)付大數(shù)目的文件描述符的時(shí)候速度更快,因?yàn)閷?duì)select()來(lái)說(shuō)內(nèi)核需要檢查大量描述符對(duì)應(yīng)的fd_set中的每一個(gè)比特位,比較費(fèi)時(shí)。
3)select()可以監(jiān)控的文件描述符數(shù)目是固定的,相對(duì)來(lái)說(shuō)也較少(1024或2048)。如果需要監(jiān)控?cái)?shù)值比較大的文件描述符,或是分布得很稀疏的較少的描述符,效率也會(huì)很低。而對(duì)于poll()函數(shù)來(lái)說(shuō),就可以創(chuàng)建特定大小的數(shù)組來(lái)保存監(jiān)控的描述符,而不受文件描述符值大小的影響,而且poll()可以監(jiān)控的文件數(shù)目遠(yuǎn)大于select()。
4)對(duì)于select()來(lái)說(shuō),所監(jiān)控的fd_set在select返回之后會(huì)發(fā)生變化,所以在下一次進(jìn)入select()之前都需要重新初始化需要監(jiān)控的fd_set,poll()函數(shù)將監(jiān)控的輸入和輸出事件分開(kāi),允許被監(jiān)控的文件數(shù)組被復(fù)用而不需要重新初始化。
5)select()函數(shù)的超時(shí)參數(shù)在返回時(shí)也是未定義的,考慮到可移植性,每次在超時(shí)之后在下一次進(jìn)入到select()之前都需要重新設(shè)置超時(shí)參數(shù)。
(2)select()的優(yōu)點(diǎn)如下所述。
1)select的可移植性更好,在某些UNIX系統(tǒng)上不支持poll().
2)select()對(duì)于超時(shí)值提供了更好的精度,而poll()是精度較差。
(3)epoll的優(yōu)點(diǎn)如下所述。
1)支持一個(gè)進(jìn)程打開(kāi)大數(shù)目的socket描述符(FD)
select()最不能忍受的是一個(gè)進(jìn)程所打開(kāi)的FD是有一定限制的,由FD_SETSIZE的默認(rèn)值是1024/2048。對(duì)于那些需要支持上萬(wàn)連接數(shù)目的IM服務(wù)器來(lái)說(shuō)顯然太少了。這時(shí)候可以選擇修改這個(gè)宏然后重新編譯內(nèi)核。不過(guò)epoll則沒(méi)有這個(gè)限制,它所支持的FD上限是最大可以打開(kāi)文件的數(shù)目,這個(gè)數(shù)字一般大于2048.舉個(gè)例子,在1GB內(nèi)存的空間中這個(gè)數(shù)字一般是10萬(wàn)左右,具體數(shù)目可以使用cat/proc/sys/fs/file-max查看,一般來(lái)說(shuō)這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大。
2)IO效率不隨FD數(shù)目增加而線性下降。
傳統(tǒng)的select/poll另一個(gè)致命弱點(diǎn)就是當(dāng)你擁有一個(gè)很大的socket集合,不過(guò)由于網(wǎng)絡(luò)延遲,任一時(shí)間只有部分的socket是“活躍”的,但是selecct/poll每次調(diào)用都會(huì)線性掃描全部的集合,導(dǎo)致效率呈現(xiàn)線性下降。但是epoll不存在這個(gè)問(wèn)題,它只會(huì)對(duì)“活躍”的socket進(jìn)行操作——這是因?yàn)樵趦?nèi)核中實(shí)現(xiàn)epoll是根據(jù)每個(gè)fd上面的callback函數(shù)實(shí)現(xiàn)的。那么,只有“活躍”的socket才會(huì)主動(dòng)去調(diào)用callback函數(shù),其他idle狀態(tài)socket則不會(huì),在這個(gè)點(diǎn)上,epoll實(shí)現(xiàn)了一個(gè)“偽”AIO,因?yàn)檫@時(shí)候推動(dòng)力由Linux內(nèi)核提供。
3)使用mmap加速內(nèi)核與用戶(hù)空間的消息傳遞
這點(diǎn)實(shí)際上涉及epoll的具體實(shí)現(xiàn)。無(wú)論是selecct、poll還是epoll都需要內(nèi)核把fd消息通知給用戶(hù)空間,如何避免不必要的內(nèi)存拷貝就顯得尤為重要。在這點(diǎn)上,epoll是通過(guò)內(nèi)核與用戶(hù)空間mmap處于同一塊內(nèi)存實(shí)現(xiàn)的。
對(duì)于poll來(lái)說(shuō)需要將用戶(hù)傳入的pollfd數(shù)組拷貝到內(nèi)核空間,因?yàn)榭截惒僮骱蛿?shù)組長(zhǎng)度相關(guān),時(shí)間上來(lái)看,這是一個(gè)O(n)操作,當(dāng)事情發(fā)生后,poll將獲得的數(shù)據(jù)傳送到用戶(hù)空間,并執(zhí)行釋放內(nèi)存和剝離等待隊(duì)列等工作,向用戶(hù)空間拷貝數(shù)據(jù)與剝離等待隊(duì)列等操作的時(shí)間復(fù)雜度同樣是O(n)。
?
轉(zhuǎn)載于:https://www.cnblogs.com/wuyepeng/p/10167751.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
- 上一篇: windows下多进程加协程并发模式
- 下一篇: Parallel学习