關於iocp學習

2021-06-22 09:03:35 字數 3803 閱讀 2053

先給出iocp的定義然後給出它的實現方法,最後剖析乙個echo程式來為您撥開iocp的謎雲,除去你心中對iocp的煩惱。ok,但我不能保證你明白iocp的一切,但我會盡我最大的努力。以下是我會在這篇文章中提到的相關技術:

i/o埠

同步/非同步

堵塞/非堵塞

服務端/客戶端

多執行緒程式設計

winsock api 2.0

在這之前,我曾經開發過乙個專案,其中一塊需要網路支援,當時還考慮到了**的可移植性,只要使用select,connect,accept,listen,send還有recv,再加上幾個#ifdef的封裝以用來處理winsock和bsd套接字[socket]中間的不相容性,乙個網路子系統只用了幾個小時很少的**就寫出來了,至今還讓我很回味。那以後很長時間也就沒再碰了。

什麼是iocp?

先讓我們看看對iocp的評價

i/o完成埠可能是win32提供的最複雜的核心物件。

[advanced windows 3rd] jeffrey richter

這是[iocp]實現高容量網路伺服器

的最佳方法。

microsoft corporation

完成埠模型提供了最好的伸縮性。這個模型非常適用來處理數百乃至上千個套接字。

[windows網路程式設計2nd] anthony jones & jim ohlund

i/o completion ports特別顯得重要,因為它們是唯一適用於高負載伺服器[必須同時維護許多連線線路]的乙個技術。completion ports利用一些執行緒,幫助平衡由i/o請求所引起的負載。這樣的架構特別適合用在smp系統中產生的」scalable」伺服器。

[win32多執行緒程式設計] jim beveridge & robert wiener

看來我們完全有理由相信iocp是大型網路架構的首選。那iocp到底是什麼呢?

微軟在winsock2中引入了iocp這一概念 。iocp全稱i/o completion port,中文譯為i/o完成埠。iocp是乙個非同步i/o的api,它可以高效地將i/o事件通知給應用程式。與使用select()或是其它非同步方法不同的是,乙個套接字[socket]與乙個完成埠關聯了起來,然後就可繼續進行正常的winsock操作了。然而,當乙個事件發生的時候,此完成埠就將被作業系統加入乙個佇列中。然後應用程式可以對核心層進行查詢以得到此完成埠。

完成埠中所謂的[埠]並不是我們在tcp/ip中所提到的埠,可以說是完全沒有關係。我到現在也沒想通乙個i/o裝置和埠[iocp中的port]有什麼關係。估計這個埠也迷惑了不少人。iocp只不過是用來進行讀寫操作,和檔案i/o倒是有些類似。既然是乙個讀寫裝置,我們所能要求它的只是在處理讀與寫上的高效。在文章的第三部分你會輕而易舉的發現iocp設計的真正用意。

iocp和網路又有什麼關係?

int main()

return 0;

}相信只要寫過網路的朋友,應該對這樣的結構在熟悉不過了。accept後執行緒被掛起,等待乙個客戶發出請求,而後建立新執行緒來處理請求。當新執行緒處理客戶請求時,起初的執行緒迴圈回去等待另乙個客戶請求。處理客戶請求的執行緒處理完畢後終結。

在上述的併發模型中,對每個客戶請求都建立了乙個執行緒。其優點在於等待請求的執行緒只需做很少的工作。大多數時間中,該執行緒在休眠[因為recv處於堵塞狀態]。

但是當併發模型應用在伺服器端[基於windows nt],windows nt小組注意到這些應用程式的效能沒有預料的那麼高。特別的,處理很多同時的客戶請求意味著很多執行緒併發地執行在系統中。因為所有這些執行緒都是可執行的[沒有被掛起和等待發生什麼事],microsoft意識到nt核心花費了太多的時間來轉換執行執行緒的上下文[context],執行緒就沒有得到很多cpu時間來做它們的工作。

大家可能也都感覺到並行模型的瓶頸在於它為每乙個客戶請求都建立了乙個新執行緒。建立執行緒比起建立程序開銷要小,但也遠不是沒有開銷的。

我們不妨設想一下:如果事先開好n個執行緒,讓它們在那hold[堵塞],然後可以將所有使用者的請求都投遞到乙個訊息佇列中去。然後那n個執行緒逐一從訊息佇列中去取出訊息並加以處理。就可以避免針對每乙個使用者請求都開執行緒。不僅減少了執行緒的資源,也提高了執行緒的利用率。理論上很不錯,你想我等泛泛之輩都能想出來的問題,microsoft又怎會沒有考慮到呢?!

這個問題的解決方法就是乙個稱為i/o完成埠的核心物件,他首次在windows nt3.5中被引入。

其實我們上面的構想應該就差不多是iocp的設計機理。其實說穿了iocp不就是乙個訊息佇列嘛!你說這和[埠]這兩字有何聯絡。我的理解就是iocp最多是應用程式和作業系統溝通的乙個介面罷了。

至於iocp的具體設計那我也很難說得上來,畢竟我沒看過實現的**,但你完全可以進行模擬,只不過效能可能…,如果想深入理解iocp, jeffrey ritchter的advanced windows 3rd其中第13章和第14張有很多寶貴的內容,你可以拿來窺視一下系統是如何完成這一切的。

實現方法

microsoft為iocp提供了相應的api函式,主要的就兩個,我們逐一的來看一下:

handle createiocompletionport (

handle filehandle,              // handle to file

handle existingcompletionport,  // handle to i/o completion port

ulong_ptr completionkey,        // completion key

dword numberofconcurrentthreads // number of threads to execute concurrently

);在討論各引數之前,首先要注意該函式實際用於兩個截然不同的目的:

1.用於建立乙個完成埠物件

2.將乙個控制代碼[handle]和完成埠關聯到一起

在建立乙個完成乙個埠的時候,我們只需要填寫一下numberofconcurrentthreads這個引數就可以了。它告訴系統乙個完成埠上同時允許執行的執行緒最大數。在預設情況下,所開執行緒數和cpu數量相同,但經驗給我們乙個公式:

執行緒數 = cpu數 * 2 + 2

要使完成埠有用,你必須把它同乙個或多個裝置相關聯。這也是呼叫createiocompletionport完成的。你要向該函式傳遞乙個已有的完成埠的控制代碼,我們既然要處理網路事件,那也就是將客戶的socket作為handle傳進去。和乙個完成鍵[對你有意義的乙個32位值,也就是乙個指標,作業系統並不關心你傳什麼]。每當你向埠關聯乙個裝置時,系統向該完成埠的裝置列表中加入一條資訊紀錄。

另乙個api就是

bool getqueuedcompletionstatus(

handle completionport,        // handle to completion port

lpdword lpnumberofbytes,      // bytes transferred

pulong_ptr lpcompletionkey,   // file completion key

dword dwmilliseconds         // optional timeout value

);根據到目前為止已經講到的東西,首先來構建乙個frame。下面為您說明了如何使用完成埠來開發乙個echo伺服器。大致如下:

1.初始化winsock

2.建立乙個完成埠

3.根據伺服器執行緒數建立一定量的執行緒數

4.準備好乙個socket進行bind然後listen

5.進入迴圈accept等待客戶請求

6.建立乙個資料結構容納socket和其他相關資訊

7.將連進來的socket同完成埠相關聯

8.投遞乙個準備接受的請求

以後就不斷的重複5至8的過程

iocp埠斷開 iocp 關閉 學步園

1.完成埠針對的是控制代碼,只要控制代碼可進行重疊io操作的都可以使用。2.基本流程為 用無引數的createiocompleteport方法建立完成埠。建立getqueuedcompletionstatus迴圈執行緒 建立關聯控制代碼。用帶引數的createiocompleteport方法繫結關聯...

深入解析IOCP

1.介紹 1.1 高併發伺服器 1 要求大規模的連線 會話可能同時進行 2 列子 web 伺服器,郵件伺服器 1.2 執行緒池架構 1 每個連線分配乙個執行緒,將導致過多的執行緒。2 執行緒消耗記憶體,比如堆疊等等。2.執行緒模型 2.1 基於會話模型 1 每個執行緒服務於乙個客戶端,比如http ...

IOCP模型總結

呼叫的步驟如下 抽象出乙個完成埠大概的處理流程 1 建立乙個完成埠。2 建立乙個執行緒a。3 a執行緒迴圈呼叫getqueuedcompletionstatus 函式來得到io操作結果,這個函式是個阻塞函式。4 主線程迴圈裡呼叫accept等待客戶端連線上來。5 主線程裡accept返回新連線建立以...