網路程式設計 完成埠IOCP

2021-06-01 21:46:24 字數 3697 閱讀 1965

分類: 網路程式設計

2009-12-31 11:20

755人閱讀收藏 

舉報

裝置—windows作業系統上允許通訊的任何東西,比如檔案、目錄、序列口、並行口、郵件槽、命名管道、無名管道、套接字、控制台、邏輯磁碟、物理磁碟等。絕大多數與裝置打交道的函式都是createfile/readfile/writefile等。所以我們不能看到**file函式就只想到檔案裝置。

與裝置通訊有兩種方式,同步方式和非同步方式。同步方式下,當呼叫readfile函式時,函式會等待系統執行完所要求的工作,然後才返回;非同步方式下,readfile這類函式會直接返回,系統自己去完成對裝置的操作,然後以某種方式通知完成操作。

重疊i/o—顧名思義,當你呼叫了某個函式(比如readfile)就立刻返回做自己的其他動作的時候,同時系統也在對i/0裝置進行你要求的操作,在這段時間內你的程式和系統的內部動作是重疊的,因此有更好的效能。所以,重疊i/o是用於非同步方式下使用i/o裝置的。

完成埠—是一種windows核心物件。完成埠用於非同步方式的重疊i/0情況下,當然重疊i/o不一定非使用完成埠不可,還有裝置核心物件、事件物件、告警i/0等。但是完成埠內部提供了執行緒池的管理,可以避免反覆建立執行緒的開銷,同時可以根據cpu的個數靈活的決定執行緒個數,而且可以讓減少執行緒排程的次數從而提高效能。

view plain

typedef

struct

;  pvoid

pointer;  

};  

handle

hevent;       

//如果不使用,就務必設為0,否則請賦乙個有效的event控制代碼

下面是非同步方式使用readfile的乙個例子

view plain

//假定其他引數都已經被初始化

readfile(hfile,buffer,sizeof

這樣就完成了非同步方式讀檔案的操作,然後readfile函式返回,由作業系統做自己的事情吧

view plain

bool

andle        hfile,  

lpdword

lpcbtransfer,  

//成功傳輸了多少位元組數

bool

fwait                  

//true只有當操作完成才返回,false直接返回,如果操作沒有完成,通過調

//用getlasterror ( )函式會返回error_io_incomplete

);  

完成埠是乙個核心物件,使用時他總是要和至少乙個有效的裝置控制代碼進行關聯,完成埠是乙個複雜的核心物件,建立它的函式是:

view plain

handle

createiocompletionport(  

in handle

filehandle,  

in handle

existingcompletionport,  

in ulong_ptr

completionkey,  

in dword

numberofconcurrentthreads );  

通常建立工作分兩步:

第一步,建立乙個新的完成埠核心物件,可以使用下面的函式:

view plain

handle

createnewcompletionport(

dword

dwnumberofthreads)  

;  

第二步,將剛建立的完成埠和乙個有效的裝置控制代碼關聯起來,可以使用下面的函式:

view plain

bool

assicoatedevicewithcompletionport(

handle

hcompport,

handle

hdevice,

dword

dwcompkey)  

;  

說明createiocompletionport函式也可以一次性的既建立完成埠物件,又關聯到乙個有效的裝置控制代碼

completionkey是乙個可以自己定義的引數,我們可以把乙個結構的位址賦給它,然後在合適的時候取出來使用,最好要保證結構裡面的記憶體不是分配在棧上,除非你有十分的把握記憶體會保留到你要使用的那一刻。

numberofconcurrentthreads通常用來指定要允許同時執行的的執行緒的最大個數。通常我們指定為0,這樣系統會根據cpu的個數來自動確定。

完成埠可以幫助我們管理執行緒池,但是執行緒池中的執行緒需要我們使用beginthreadex來建立,憑什麼通知完成埠管理我們的新執行緒呢?答案在函式getqueuedcompletionstatus。 該函式原型:

view plain

bool

getqueuedcompletionstatus(  

in handle

completionport,  

out lpdword

lpnumberofbytestransferred,  

out pulong_ptr

lpcompletionkey,  

in dword

dwmilliseconds  

);  

這個函式試圖從指定的完成埠的i/0完成佇列中抽取紀錄。只有當重疊i/o動作完成的時候,完成佇列中才有紀錄。凡是呼叫這個函式的執行緒將被放入到完成埠的等待執行緒佇列中,因此完成埠就可以在自己的執行緒池中幫助我們維護這個執行緒。

完成埠的i/0完成佇列中存放了當重疊i/0完成的結果— 一條紀錄,該紀錄擁有四個字段,前三項就對應getqueuedcompletionstatus函式的2、3、4引數,最後乙個欄位是錯誤資訊dwerror。我們也可以通過呼叫postqueudcompletionstatus模擬完成了乙個重疊i/0操作。

當i/0完成佇列中出現了紀錄,完成埠將會檢查等待執行緒佇列,該佇列中的執行緒都是通過呼叫getqueuedcompletionstatus函式使自己加入佇列的。等待執行緒佇列很簡單,只是儲存了這些執行緒的id。完成埠會按照後進先出的原則將乙個執行緒佇列的id放入到釋放執行緒列表中,同時該執行緒將從等待getqueuedcompletionstatus函式返回的睡眠狀態中變為可排程狀態等待cpu的排程。

基本上情況就是如此,所以我們的執行緒要想成為完成埠管理的執行緒,就必須要呼叫getqueuedcompletionstatus函式。出於效能的優化,實際上完成埠還維護了乙個暫停執行緒列表,具體細節可以參考《windows高階程式設計指南》,我們現在知道的知識,已經足夠了。

completionkey被儲存在完成埠的裝置表中,是和裝置控制代碼一一對應的,我們可以將與裝置控制代碼相關的資料儲存到completionkey中,或者將completionkey表示為結構指標,這樣就可以傳遞更加豐富的內容。這些內容只能在一開始關聯完成埠和裝置控制代碼的時候做,因此不能在以後動態改變。

很多執行緒為了不止一次的執行非同步資料處理,需要使用如下語句

view plain

while

(true

)    

完成埠iocp和重疊埠

windows下的iocp和 linux下的epoll epoll我還沒有研究過 都是屬於socket 網路程式設計的範疇.不過其特色是 用固定很少的執行緒去管理成千上萬個socket連線.其相當於 非同步通訊 普通socket是同步,同步 可能要乙個執行緒乙個socket鏈結 去做,由於系統可以執...

小心使用IOCP完成埠

s createsocket 假定s返回值是10 createiocompletionport s,m hcompletionport,dword ptr a,0 wsasend s,wsasend s,wsasend s,wsasend s,wsasend s,這個時候,完成埠裡累計了多條跟s相關...

IOCP 完成埠 開發手記 3

當建立iocp埠後,就要初始化連線監聽,這跟一般的socket是沒有什麼區別的,當然要把它關聯到iocp,否則就不會從iocp那裡得響應.接著就會建立滿足需要的接收請求,這樣就會收到連線進來.如果有連線進來,就會收在getqueued pletionstatus函式裡收到前面發出的請求包,接著就進行...