1. 程式人生 > >網路io模型總結

網路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者也可以歸為多程序單執行緒這種模型