網(wǎng)絡(luò)系列x-Linux網(wǎng)絡(luò)IO模型

NIO TODO 歸檔到Linux下

結(jié)合Linux 了解socket原理 什么多路復(fù)用 selector epoll poll

時(shí)間: 1個(gè)星期(不知道什么時(shí)候創(chuàng)建的這些文件,反正感覺很久了,今天2019-11-14先初探一把),學(xué)習(xí)參照

http://www.itdecent.cn/p/486b0965c296

http://www.itdecent.cn/p/aed6067eeac9

https://juejin.im/post/5c725dbe51882575e37ef9ed

https://woshijpf.github.io/linux/2017/07/10/Linux-IO%E6%A8%A1%E5%9E%8B.html

https://tech.youzan.com/yi-bu-wang-luo-mo-xing/

背景知識(shí)一

同步與異步

所謂同步就是一個(gè)任務(wù)的完成需要依賴另外一個(gè)任務(wù)時(shí),只有等待被依賴的任務(wù)完成后,依賴的任務(wù)才能算完成,這是一種可靠的任務(wù)序列。要么成功都成功,失敗都失敗,兩個(gè)任務(wù)的狀態(tài)可以保持一致。

所謂異步是不需要等待被依賴的任務(wù)完成,只是通知被依賴的任務(wù)要完成什么工作,依賴的任務(wù)也立即執(zhí)行,只要自己完成了整個(gè)任務(wù)就算完成了。至于被依賴的任務(wù)最終是否真正完成,依賴它的任務(wù)無法確定,所以它是不可靠的任務(wù)序列。

如果異步調(diào)用,調(diào)用方獲取異步任務(wù)結(jié)果方式

  1. 設(shè)置共享數(shù)據(jù),執(zhí)行方執(zhí)行完畢后將結(jié)果設(shè)置到該共享數(shù)據(jù)中,調(diào)用方不斷輪詢查詢?cè)摴蚕頂?shù)據(jù)

  2. 執(zhí)行方執(zhí)行完畢后通知調(diào)用方

  3. 執(zhí)行方執(zhí)行完畢后通過回調(diào)函數(shù)將結(jié)果告知調(diào)用方(這不也是一種通知方式嗎?)

阻塞與非阻塞

阻塞和非阻塞這兩個(gè)概念與程序(線程)等待消息通知(無所謂同步或者異步)時(shí)的狀態(tài)有關(guān)。也就是說阻塞與非阻塞主要是程序(線程)等待消息通知時(shí)的狀態(tài)角度來說的。

阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起,一直處于等待消息通知,不能夠執(zhí)行其他業(yè)務(wù)。函數(shù)只有在得到結(jié)果之后才會(huì)返回。

非阻塞和阻塞的概念相對(duì)應(yīng),指在不能立刻得到結(jié)果之前,該函數(shù)不會(huì)阻塞當(dāng)前線程,而會(huì)立刻返回。雖然表面上看非阻塞的方式可以明顯的提高CPU的利用率,但是也帶了另外一種后果就是系統(tǒng)的線程切換增加。增加的CPU執(zhí)行時(shí)間能不能補(bǔ)償系統(tǒng)的切換成本需要好好評(píng)估。

同步/異步討論的是調(diào)用方獲取任務(wù)執(zhí)行結(jié)果的方式

阻塞/非阻塞討論的是調(diào)用方在等待任務(wù)結(jié)果時(shí)是否還能干其他事

按照上面兩種維度來組合,就會(huì)有 同步阻塞異步阻塞 ,同步非阻塞異步非阻塞四種實(shí)現(xiàn)方案

背景知識(shí)二

用戶空間與內(nèi)核空間

在32位操作系統(tǒng)中,尋址空間(虛擬地址)是2^32(4G),為了保證內(nèi)核安全,禁止用戶進(jìn)程直接操作內(nèi)核,操作系統(tǒng)將虛擬地址空間劃分為兩部分,將0xC0000000到0xFFFFFFFF(1G)劃給內(nèi)核使用,稱為內(nèi)核空間(也就是內(nèi)核態(tài)?),剩余的0x00000000到0xBFFFFFFF(3G)劃分給用戶進(jìn)程使用,稱為用戶空間(也就是用戶態(tài)?)

那64位操作系統(tǒng)豈不是可以管理2^64(17179869184G)?理論上是這樣的,但實(shí)際中目前只用到了48位(262144G)

https://www.zhihu.com/question/28638698

進(jìn)程阻塞

正在執(zhí)行的進(jìn)程,由于期待的某些事件未發(fā)生,如請(qǐng)求系統(tǒng)資源失敗、等待某種操作的完成、新數(shù)據(jù)尚未到達(dá)或無新工作做等,則由系統(tǒng)自動(dòng)執(zhí)行阻塞原語(Block),使自己由運(yùn)行狀態(tài)變?yōu)樽枞麪顟B(tài)??梢?,進(jìn)程的阻塞是進(jìn)程自身的一種主動(dòng)行為,也因此只有處于運(yùn)行態(tài)的進(jìn)程(獲得CPU),才可能將其轉(zhuǎn)為阻塞狀態(tài)。當(dāng)進(jìn)程進(jìn)入阻塞狀態(tài),是不占用CPU資源的。

Linux IO模型

網(wǎng)絡(luò)IO的本質(zhì)是socket的讀取,socket在linux系統(tǒng)被抽象為流,IO可以理解為對(duì)流的操作

像Java世界中切皆對(duì)象一樣,Linux中一切皆文件。socket也是一個(gè)文件又是怎么體現(xiàn)的?

https://blog.csdn.net/kingshown_WZ/article/details/52103327

https://blog.csdn.net/YEYUANGEN/article/details/6799575

對(duì)于tcp傳輸,需要源IP/端口,目標(biāo)IP/端口四元組,每創(chuàng)建一個(gè)連接(socket?),客戶端端內(nèi)核會(huì)隨機(jī)分配一個(gè)端口,但是服務(wù)端只有一個(gè)端口,那對(duì)于多個(gè)連接,服務(wù)端是怎么確定該數(shù)據(jù)包屬于一個(gè)進(jìn)程中的哪個(gè)連接呢?

對(duì)于一次IO訪問(比如read),數(shù)據(jù)會(huì)先被拷貝到操作系統(tǒng)內(nèi)核的緩沖區(qū)中,然后才會(huì)從操作系統(tǒng)內(nèi)核的緩沖區(qū)拷貝到應(yīng)用程序的地址空間。所以,當(dāng)一個(gè)read操作發(fā)生時(shí),它會(huì)經(jīng)歷兩個(gè)階段:

  1. 第一階段:等待數(shù)據(jù)準(zhǔn)備
  2. 第二階段:將數(shù)據(jù)從內(nèi)核復(fù)制到進(jìn)程中

對(duì)于socket流而言,

  1. 第一步:等待網(wǎng)絡(luò)上的數(shù)據(jù)分組到達(dá),然后被復(fù)制到內(nèi)核的某個(gè)緩沖區(qū)
  2. 第二步:將數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到應(yīng)用進(jìn)程緩沖區(qū)

網(wǎng)絡(luò)IO模型有以下5中

  • 同步阻塞IO Blocking IO
  • 同步非阻塞IO Non-Blocking IO
  • 多路復(fù)用IO Multiplexing IO
  • 信號(hào)驅(qū)動(dòng)IO Signal Driven IO(實(shí)際中不常用)
  • 異步IO Asynchronous IO
一、Blocking IO

在這個(gè)模型中,用戶進(jìn)程執(zhí)行一個(gè)系統(tǒng)調(diào)用(recv/recvfrom),這會(huì)導(dǎo)致進(jìn)程阻塞(不占用CPU時(shí)間片),直到數(shù)據(jù)準(zhǔn)備好,并將數(shù)據(jù)復(fù)制到進(jìn)程緩沖區(qū),recv/recvfrom函數(shù)返回結(jié)果,最后進(jìn)程再處理數(shù)據(jù)。這種模型從數(shù)據(jù)處理角度來講是最及時(shí)的,因?yàn)閿?shù)據(jù)被復(fù)制到進(jìn)程緩沖區(qū)后,進(jìn)程能及時(shí)處理。處理流程圖如下:

image

應(yīng)用進(jìn)程在兩個(gè)階段都被阻塞了

關(guān)于recv和recvfrom的區(qū)別,見https://www.cnblogs.com/p2liu/archive/2013/04/17/6048755.html

二、Non-Blocking IO

以非阻塞模式打開,每隔一段時(shí)間調(diào)用recv/recvfrom,如果數(shù)據(jù)未準(zhǔn)備好,會(huì)立即返回一個(gè)錯(cuò)誤碼。這個(gè)過程稱為輪詢。應(yīng)用進(jìn)程調(diào)用recv/recvfrom時(shí)是會(huì)被阻塞的,但是在兩次調(diào)用之間是進(jìn)程是未被阻塞的,可以獲取CPU時(shí)間片。從內(nèi)核角度來看,當(dāng)收到recv/recvfrom調(diào)用時(shí),如果數(shù)據(jù)未準(zhǔn)備好,則立即返回錯(cuò)誤碼,如果數(shù)據(jù)已經(jīng)準(zhǔn)備好了,則將數(shù)據(jù)復(fù)制到進(jìn)程緩沖區(qū)。

image

跟同步阻塞模型相比,同步非阻塞模型

優(yōu)點(diǎn):在輪詢期間可以執(zhí)行其他任務(wù)

缺點(diǎn):因?yàn)槭枪潭〞r(shí)間間隔輪詢的(并且這個(gè)間隔不會(huì)太短),所以數(shù)據(jù)可能會(huì)在兩次查詢間隔時(shí)就已經(jīng)準(zhǔn)備好了,會(huì)導(dǎo)致響應(yīng)時(shí)間加大,吞吐量下降。

三、Multiplexing IO

在討論前面兩種IO模型時(shí),都是基于單個(gè)socket來討論的,實(shí)際上一個(gè)系統(tǒng)同時(shí)會(huì)有多個(gè)socket(屬于同一個(gè)用戶進(jìn)程或多個(gè)用戶進(jìn)程)。每個(gè)socket都需要輪詢或被阻塞,如果有單獨(dú)一個(gè)人(這里我不知道用進(jìn)程、線程還是什么其他東西來描述更準(zhǔn)確,等后續(xù)再來完善吧),如果數(shù)據(jù)準(zhǔn)備好了,告訴用戶進(jìn)程,在這之前用戶進(jìn)程可以安心干其他事就好了。Linux下的select,poll,epoll就是來干”查看“的工作的,如果查詢得知數(shù)據(jù)已經(jīng)準(zhǔn)備好了,就通知用戶進(jìn)程,用戶進(jìn)程再調(diào)用recv/recvfrom來獲取數(shù)據(jù)

select ,poll,epoll三者功能是一樣的,但是epoll是select和poll的改進(jìn)版,具體區(qū)別見https://www.cnblogs.com/anker/p/3265058.html

我的理解,所謂的多路復(fù)用,就是將”查詢數(shù)據(jù)狀態(tài)“和”復(fù)制數(shù)據(jù)“兩個(gè)操作分開來,并”查詢操作“實(shí)現(xiàn)了批量化,可以一次查詢多個(gè)socket的數(shù)據(jù)狀態(tài),將已經(jīng)準(zhǔn)備好的socket相關(guān)信息返回回來,用戶進(jìn)程再單獨(dú)調(diào)用recv/recvfrom。跟同步非阻塞模型相比,節(jié)省了查詢所做的工作量。

select 操作還是由用戶進(jìn)程調(diào)用,并且調(diào)用過程中也會(huì)被阻塞,一旦有一個(gè)socket的數(shù)據(jù)準(zhǔn)備好了就會(huì)返回。來個(gè)不準(zhǔn)確的總結(jié),多路復(fù)用將部分工作批量化了,單個(gè)的操作跟同步非阻塞模型來說類似。

因此,對(duì)于單個(gè)socket來說,多路復(fù)用并沒有什么優(yōu)勢(shì),其優(yōu)勢(shì)體現(xiàn)在同時(shí)處理多個(gè)socket場景下,能實(shí)現(xiàn)高并發(fā),什么C10K場景,比如Nginx,Redis?

image

從整個(gè)IO流程來看,前面三種模型都是用戶進(jìn)程主動(dòng)等待并且向內(nèi)核查詢數(shù)據(jù)狀態(tài),因此三者都?xì)w為同步模型*

四、Asynchronous IO

相對(duì)于同步IO,異步IO不是順序執(zhí)行。用戶進(jìn)程進(jìn)行aio_read系統(tǒng)調(diào)用之后,無論內(nèi)核數(shù)據(jù)是否準(zhǔn)備好,都會(huì)直接返回給用戶進(jìn)程,然后用戶態(tài)進(jìn)程可以去做別的事情。等到socket數(shù)據(jù)準(zhǔn)備好了,內(nèi)核直接復(fù)制數(shù)據(jù)給進(jìn)程,然后從內(nèi)核向進(jìn)程發(fā)送通知IO兩個(gè)階段,進(jìn)程都是非阻塞的

image

使用場景

五、Signal Driven IO

暫時(shí)不了解了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)自: http://www.itdecent.cn/p/486b0965c296 http://www.jia...
    demop閱讀 4,117評(píng)論 1 21
  • 一. 操作系統(tǒng)概念 操作系統(tǒng)位于底層硬件與應(yīng)用軟件之間的一層.工作方式: 向下管理硬件,向上提供接口.操作系統(tǒng)進(jìn)行...
    月亮是我踢彎得閱讀 6,145評(píng)論 3 28
  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口,提供良好的抽象接口。 管理調(diào)度進(jìn)程,并將多個(gè)進(jìn)程對(duì)硬件...
    drfung閱讀 3,747評(píng)論 0 5
  • 注:1)本人非科班出身,文章的來源主要是基于一些能找到的資料,在理解的基礎(chǔ)上做一些總結(jié)歸納,以期對(duì)IO相關(guān)的知識(shí)體...
    Drew_Zhong閱讀 1,123評(píng)論 0 2
  • python之路——IO模型 IO模型介紹 為了更好地了解IO模型,我們需要事先回顧下:同步、異步、阻塞、非阻塞 ...
    go以恒閱讀 593評(píng)論 0 2

友情鏈接更多精彩內(nèi)容