2012-09-03 48 views
0

過去幾天我一直在考慮如何解決我面臨的一個問題,並且我試圖研究這個主題,但並不知道我能做什麼。IOCP在同一容器中的多個套接字完成端口

我在同一個結構中有兩個套接字,它們都具有相同的completionport。問題是,他們都使用不同的協議。有沒有辦法,我可以找出哪個套接字被觸發?他們叫game_socket和client_socket

示例代碼會是這樣的......

while (true) { 
error = GetQueuedCompletionStatus(CompletionPort, &BytesTransfered, (PULONG_PTR)&Key, &lpOverlapped, 0); 
srvc = CONTAINING_RECORD (lpOverlapped, client , ol); 
if (error == TRUE) { 
cout << endl << "SOCKET: [" << srvc->client_socket << "] TRIGGERED - WORKER THREAD" << endl; 
cout << endl << "BytesTransfered: [" << BytesTransfered << "]" << endl; 

if (srvc->game_client triggered) { 
// .. this code 
} else { 

// .. this code 
} 

任何意見或幫助將不勝感激:)

回答

2

您正在使用的重疊延伸結構非常適合爲a特定連接實例。例如,該結構不僅應包含正在執行操作的套接字,還應包含操作。例如,可以讀寫的套接字上的IO完成應反映IO請求開始時的狀態。大多數基於IOCP的客戶端/服務器代碼的例子都將證明這種普遍的意識形態。

在你的情況下,你不應該對兩個不同的套接字使用相同的OVERLAPPED結構,這有兩個潛在的獨立動作。如果套接字在某種意義上是「相關的」,那麼應該在OVERLAPPED結構之外跟蹤和維護套接字。每個人都應該有自己獨特的結構來完成自己獨特的IO完成。其他任何事情都誠實地要求頭痛。

所有的說法,它並沒有出現你的用例可以遠離轉換你目前的計劃,以適應我所描述的。我總是不願意給出「你不應該這樣做」的答案,因爲我完全不喜歡聽到他們自己,但在這種情況下這是不可或缺的。

所有最優秀的。

+0

我怕的就是這個。正如我已經嘗試了很多事情,WSAEnumNetworkEvents與WSAEventSelect,但沒有任何工作。 :( – User

+0

它可能並不如你想象的那麼糟糕,你可以在多個套接字中使用相同的IOCP而不會出現問題,只要確保每個IO請求都與一個IO請求相關聯,並且只有一個OVERLAPPED結構。套接字在某個對象實例中進行管理,並且它們都可能在IOCP上等待,那麼每個套接字都可能具有一個擴展的OVERLAPPED結構,該結構鏈接到該對象並且*標識哪個套接字參與該OVERLAPPED數據表示的IO請求。我希望這是有道理的,你可以做到這一點,再想一想吧。 – WhozCraig

+0

我有點想到我必須這樣做!謝謝你的回覆,我一定會用一些小的測試服務器。:) – User

3

使用IOCP時,您有兩項用戶數據可供您在每次異步操作中使用。

第一個是「每個連接」數據的完成鍵,當您通過調用帶有套接字/文件句柄和現有完成端口的CreateIoCompletionPort()將文件句柄或套接字與完成端口相關聯時,該關鍵字被設置。對於給定連接,每次調用GetQueuedCompletionStatus()時都會返回此值。

第二個是「每個操作」數據的「擴展重疊」結構。每個併發操作都必須爲其分配一個唯一的重疊結構。

在上面的設計中,您應該使用「每個連接」數據來識別您的連接。你有兩個鏈接(套接字)被鏈接,所以我會有兩個鏈接類,每個鏈接一個。如果你使用C而不是C++,類(或者結構體)將包含套接字,一個指向連接的另一半的指針和一個指示它是哪種類型連接的標誌。如果使用C++,這兩個類將從一個公共基類派生出來,以便您可以調用成員函數來確定完成鍵所代表的連接類型。如果使用C使用歧視聯盟。

然後,您只需將完成鍵強制轉換爲基礎,然後確定具有哪種連接類型並將其轉換爲正確的類/結構。您現在知道該操作在哪個連接上執行。連接類可以存儲運行其協議的狀態機的所有狀態。作爲Criag提到,每個重疊結構是「每個操作都是唯一的」,在我的IOCP代碼中,這往往允許訪問數據緩衝區以進行操作,並且標誌告訴我操作是什麼(讀/寫/接受/連接等)。

一個潛在的複雜性是保持每個操作和每個連接數據的活動,直到所有使用它的未完成操作都完成爲止。我個人喜歡每個連接和每個操作數據的引用計數,但我相信還有其他方法。

我有IOCP使用這些概念(雖然不提供「兩個連接」的例子)一些示例代碼,你可以從這裏下載:http://www.serverframework.com/products---the-free-framework.html

+0

這在我看來是比接受的答案更準確的答案(儘管那一個沒有錯)。在這種情況下,'CompletionKey'值正是可以使用的值。 – Damon

+1

Damon;每個操作需要單獨的OVERLAPPED。在一個簡單的系統中,你永遠不會有一個以上的讀操作或者一個寫操作一次寫入掛起,那麼每個套接字一個單獨的OVERLAPPED就足夠了;任何更復雜的需要獨特的OVERLAPPED PER併發操作。我發現即使是簡單的事務服務器,如果下一個recv在處理當前recv完成時結束,而不是從你寫的答覆中處理相應的寫入完成後,將會更好地工作... –

+0

對不起,我的措詞是誤導性的(或確實是錯誤的)。是的,您當然需要爲每個請求提供唯一的「OVERLAPPED」存儲位置(比如sendto或者readfile),但這些只是「不透明」的塊,沒有提供操作系統在重疊操作(我用它們搭載一些其他數據)。在我上面的「用於化妝品,不是因爲它是需要的」,我想到了在排隊狀態時填入的那種垃圾「ptr-to-'OVERLAPPED」,但是再想一想,即使那樣也行不通可靠的併發線程。 – Damon

相關問題