完成端口(IOCP)的另一種設想——Socket與CompletionPort的多次關聯

 

完成端口(IOCP)的另一種設想——SocketCompletionPort的多次關聯

代碼客   http://blog.csdn.net/guestcode

本文論壇討論: http://topic.csdn.net/u/20091104/14/083f8353-e4dc-470f-b0a7-f570404ab338.html

 

先扯一下題外話。我發表過VCDelphiIOCP例程。有不少人提出了很好的建議,也有很多人提出了置疑。有自稱內核編程的人說臨界段同步不要需要進入內核態,用過臨界段的人都知道,當競爭發生的時候,“後來”的線程總被掛起,那麼線程掛起會進入什麼態?

 有人提出線程獨立的內存資源管理,可以避免的同步操作,這不失爲一個好辦法,但帶來的麻煩是,分配資源的時需要在取得“當前線程對象”上花費時間,其實臨界段在競爭不激烈的情況下導致進入內核態的機率很少,臨界段玩得的就是概率。

在工作線程和處理線程之間,有人建議最好做法是複製數據給處理線程,當然這個比較安全點,但數據複製也需要不少時間。甚至有人抨擊,HandleDatasocket連接的對象)和UserData(登錄用戶的對象)之間的指針關聯方式效率底下,認爲哈希表方式效率高,可是未必見得哈希表的操作比指針關聯方式有優越之處。

內存管理是服務器性能的關鍵,有人卻忽略了分頁內存會被交換到頁交換文件中去的可能。對象化(類)編程能夠提高開發效率,但也要注意“級數深”的對象成員及虛函數訪問的開銷。事實上操作完成端口很容易,難的是如何組織管理內存和設計合理的結構。

 

 進入正題。前面提到HandleDataUserData,做過Tcp服務開發的人都知道,每個客戶端連接都有一個Socket對象(下稱HandleData)與之對應。做過遊戲開發的人也肯定知道,在服務器端每個登錄的用戶有個對象(下稱UserData)記錄用戶信息,UserDataHandleData也是一一對應關係。但兩者很難合併爲一體(同一個數據結構或類對象),UserData是在用戶輸入ID和密碼Login之後被會創建(或池分配),用戶發送數據Logout之後會被摧毀(或回收入池),而在Logout之前,由於網絡等諸多原因,會有N次的重新連接的可能性,如果斷線不超過規定時間的話UserData是不能摧毀的,那麼UserData在其生命期內對應的HandleData就不是唯一的了。一般HandleDataUserData關聯的做法是,根據Login的用戶ID在目前的在線用戶信息列表中查找UserData,找到則關聯(未超時和Logout),找不到則創建後再關聯,此後根據關聯信息無需遍歷很快就可以知道來自這個HandleData的數據就是這個UserData的(用戶登錄頻率遠比數據收發頻率底得多,以最快方式把Socket的數據定位到用戶對象上去是高效率的一個關鍵)。他們關聯的方式有:1、使用指針關聯的,HandleData有指針指向UserDataUserData有指針指向HandleData);2、使用哈希表,用socket的值作爲索引;3UserData索引,就是登錄以後返回UserData的索引,此後客戶端發來的每個數據包裏面都包含這個的索引,但會增加數據量,一般用在Udp服務器。上面這些是常用的方式,但是否還有其它剛好的方式呢?

 瞭解完成端口的都知道,完成端口句柄和Socket關聯的參數有個完成鍵(CompletionKey),這個CompletionKey一般是HandleData(或是擔任這個角色的其它結構),通常我們僅建立一次CompletionPortSocket的關聯,因此某個客戶端從連接到斷開,CompletionKey一直是HandleData。假如有這麼個設想不知道是否行得通,就是當用戶發送ID和密碼Login之後,用UserData作爲CompletionKey再次把Socket和完成端口關聯,那麼此後的Io投遞的返回數據就可以直接對應UserData。本人信息閉塞,尚未不知道有人提過這個方法,也不知道是否行得通,也希望大家互相探討。具體做法是:

1Accept/AcceptEx階段:

CreateIoCompletionPort(Socket, CompletionPort, HandleData, 0);

2、用戶發送數據Login,獲得認證並建立UserData以後:

CreateIoCompletionPort(Socket, CompletionPort, UserData, 0);

3Disconnect之後(恢復最初關聯):

CreateIoCompletionPort(Socket, CompletionPort, HandleData, 0);

上面三步主要區別於CreateIoCompletionPort函數的第三個參數。假如行得通的話,那麼Iocp Server的編程難度相對就增大了一些,UserData 也要具備HandleData的基本功能。在測試中多次調用CreateIoCompletionPort(Socket, CompletionPort, )進行關聯操作的返回值是正確的,但尚未得知的是多次關聯對Iocp內部機制有沒有影響,以後會有怎樣的異常出現。本人也正在進一步編程求證中。

 

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章