網路io模型總結
作業系統基本概念
首先來來說下作業系統,嗯,作業系統是計算機硬體的管理軟體,是對計算機硬體的抽象,作業系統將應用程式分為使用者態和核心態,例如驅動程式就位於核心態,而我們寫的一般程式都是使用者態,包括web伺服器這些,應用程式無法直接操控硬體,只能通過系統呼叫,通過作業系統驅動io硬體,通過作業系統管理程序。
接下來說下檔案的概念,在作業系統中,檔案是對i/o的一種抽象,檔案大體包括三類
普通的檔案:包括二進位制檔案和文字檔案
目錄:就是普通檔案的一組連結串列
套接字檔案:用來與另一個程序進行跨網路通訊的檔案
套接字檔案就是通常說的socket,還有值得注意的是無論開啟什麼檔案,核心都會返回給應用程式一個檔案描述符。當關閉檔案後,核心釋放資源,同時回收檔案描述符。
程序的記憶體模型
每個程序都有獨立的上下文,它擁有完整的虛擬記憶體空間。
CPU執行程序,總是在不斷對程序的切換中,這種叫時分複用,而且時間很快,從而讓人有一種程序並行的感覺,即單個cpu在一個時刻只能做一件事
I/O流程
說下應用程式讀檔案的大致流程(寫檔案也差不多),當一個程序想要向磁碟或者接受網路資料時,它會先發起系統呼叫(可以通過異常等方式),然後將程式控制權交給作業系統,
作業系統向指定的檔案發起讀的操作,返回給程式一個檔案操作符,然後接下來就是比較有意思的地方了,因為檔案讀出來是需要時間的,檔案讀出來後會存到核心的緩衝區中(DMA),然後中斷提醒CPU,CPU再由核心緩衝區讀取到使用者程序中,在這個過程中,這段時間裡,使用者程序可以有阻塞,非阻塞,同步,非同步各種狀態
linux的I/O模型
網路IO的本質是socket的讀取,socket在linux系統被抽象為流,IO可以理解為對流的操作。對於一次IO訪問(以read舉例),資料會先被拷貝到作業系統核心的緩衝區中,然後才會從作業系統核心的緩衝區拷貝到應用程式的地址空間。所以說,當一個read操作發生時,它會經歷兩個階段:
第一階段:等待資料準備 (Waiting for the data to be ready)。 第二階段:將資料從核心拷貝到程序中 (Copying the data from the kernel to the process)。
對於socket流而言,
第一步:通常涉及等待網路上的資料分組到達,然後被複制到核心的某個緩衝區。 第二步:把資料從核心緩衝區複製到應用程序緩衝區。
linux的五種網路i/o模型
同步的概念就是在資料複製到使用者程序的這段時間內,使用者程序是不幹活
非同步是在這段時間內,使用者程序會繼續執行它後續的工作
先在同步非同步的基礎上進行簡單的分類
同步模型(synchronous IO)
- 阻塞IO(bloking IO)
- 非阻塞IO(non-blocking IO)
- 多路複用IO(multiplexing IO)
- 訊號驅動式IO(signal-driven IO)
非同步IO(asynchronous IO)
接下來進行分類的介紹
阻塞I/O
阻塞i/o就是整個過程使用者程序都是阻塞,它發起系統呼叫後就被掛起了,直到資料被搬運到緩衝區中,然後資料從緩衝區讀進使用者程序,它才被喚醒,真個過程它都處於掛起狀態(什麼都不幹)
非阻塞i/o
使用者程序發起系統呼叫後,它沒有被掛起,而是繼續執行,但它要不斷輪詢看資料是否運到核心了,資料到了核心後,使用者程序將資料從核心讀取到使用者程序
多路複用I/O
多路複用I/O比較複雜,它整個過程也是阻塞的,但不同的是它可以阻塞多個i/o,同時阻塞多個socket連線,有epoll,,poll,select等,epoll是linux最高效的,多路複用的特點是通過一種機制一個程序能同時等待多個IO檔案描述符,核心監視這些檔案描述符(套接字描述符),其中的任意一個進入讀就緒狀態,select, poll,epoll函式就可以返回。
select,poll,epoll都是核心狀態的函式呼叫
使用者程序發起系統呼叫後,處於掛起狀態,同時監聽多個socket連線,只要有其中有一個數據到達核心,使用者程序就被喚醒工作,然後將資料從核心讀取到使用者程序,其實就是由epoll,select同時監聽多個io物件,當io物件發生變化的時候,就通知使用者程序讀寫資料,進行操作
即多個io物件複用一個程序,這樣可以很充分的利用阻塞的這段時間
IO多路複用是同步阻塞模式
非同步驅動I/O
這個理論上是最好的,但在linux系統中很難實現
訊號驅動i/o
這個很少使用到
非同步IO
非同步io在linux中很難實現,但也有一種模擬非同步io的方法即多執行緒和同步阻塞io進行模擬,設定一個主執行緒,用其它執行緒進行同步io操作,當io完成時通知主執行緒去讀取程序中的資料,進行後續操作,因為是同一個程序,所以可以共享記憶體資源。進而實現類似非同步io的效果,在linux中有libev,libeio這樣的非同步io實現庫,而在windows,則使用了iocp,可以說非同步io的核心就是在子執行緒上執行io操作,在執行完畢後通知呼叫者提取相關資料。只不過linux是使用者層的執行緒池,而iocp是核心的執行緒池。
Node模型
首先說下常見的模型要麼是單程序多執行緒,要麼是多程序單執行緒,node是屬於後者
node中最重的就是包含了libuv這個,node的所有io操作都是通過它來實現的,libuv實現了非同步IO,libuv中包含一個事件佇列(可以理解為就是主執行緒),如果是網路io,它會使用epoll這種io多路複用的方式(在linux中)對io進行處理,而對於磁碟的io操作,它會採用多執行緒+阻塞io的方式進行io操作,它讀寫完資料後就將資料返回給js引擎。從而實現io操作。
最後提一點epoll這種io多路複用模型使用的很廣,redis,nginx,都不同程度使用了它,它2者也可以歸為多程序單執行緒這種模型