編寫大容量和健壯的服務(wù)器系列—處理IOCP資源釋放 [轉(zhuǎn)]
Posted on 2009-01-31 06:53 S.l.e!ep.¢% 閱讀(645) 評(píng)論(0) 編輯 收藏 引用 所屬分類: VC編寫大容量和健壯的服務(wù)器系列—處理IOCP資源釋放 2007-08-21 15:24
?
鄧立波 深圳,2007-8
作者聯(lián)系方式 :
email:???????? libodeng@gmail.com
msn:?????????? libodeng@gmail.com
tel:???? ???????? 13510275799
版權(quán)/著作權(quán)所有 (C) 2007 鄧立波 保留所有權(quán)利
警告:未經(jīng)作者許可,任何人或組織不得轉(zhuǎn)載,公開發(fā)布,拷貝,傳播本文獻(xiàn)的全部或部分
? ?
1 問題定義
一般的,我們需要在連接關(guān)閉(包括主動(dòng)或被動(dòng)關(guān)閉)時(shí)釋放以下資源:
(1) 一個(gè)或多個(gè)接收/發(fā)送緩存,一個(gè)信令緩存(用作拼包,可能一次WSARecv僅收
到半個(gè)信令,這時(shí)需要一個(gè)緩存先保存這半個(gè)信令,繼續(xù)發(fā)出WSARecv 調(diào)用,直
到接收到一個(gè)完整信令)。
(2) 調(diào)用closesocket釋放socket資源。
主要的問題是資源何時(shí)釋放,以及該在哪兒釋放。
?
2 緩存如何同socket綁定
方式一
發(fā)送緩存綁定到發(fā)送操作的OVERLAPPED中(一般通過擴(kuò)展OVERLAPPED結(jié)構(gòu)添加一個(gè)緩存指針變量),接受緩存和信令緩存綁定到接受操作的OVERLAPPED中,如果還有一些資源需要 在IOCP處理發(fā)送/接收之外的地方訪問 ,你可以再動(dòng)態(tài)分配一個(gè)的結(jié)構(gòu)體,將其指針同CompletionKey邦定
方式二
使用一個(gè)Hash表,對(duì)每個(gè)連接定義一個(gè)連接上下文,按socket值索引,把一些資源,例如信令緩存指針置于hash中的上下文。
?
方式一優(yōu)點(diǎn)是速度快(其實(shí)也快不了多少),但卻存在資源在哪兒釋放,何時(shí)釋放的問題。
對(duì)此,網(wǎng)絡(luò)上有兩篇文章討論過:
本文作者:sodme
本文出處:http://blog.csdn.net/sodme
聲明:本文可以不經(jīng)作者同意任意轉(zhuǎn)載、復(fù)制、傳播,但任何對(duì)本文的引用均須保留本文的作者、出處及本行聲明信息!謝謝!
很慚愧,我無法理解前一篇文章中作者所假設(shè)的應(yīng)用環(huán)境,因此我無法判定是否這樣真能解決問題,但至少我不放心真的這樣做,即使作者是對(duì)的,這種“獨(dú)特”的機(jī)制也會(huì)讓我對(duì)服務(wù)器的健壯性感到不安。后一文章使用引用計(jì)數(shù)的方式理論上是可行的,這個(gè)引用計(jì)數(shù)用于跟蹤你所分配的結(jié)構(gòu)體的動(dòng)態(tài)釋放,因此在所有引用到這個(gè)結(jié)構(gòu)體的地方都得做引用計(jì)數(shù)處理(increment reference或者decrement reference),更要命的是上層應(yīng)用也可能需要對(duì)這個(gè)結(jié)構(gòu)體保存一個(gè)引用(一般是保存結(jié)構(gòu)體的一個(gè)指針,即CompletionKey),因?yàn)榉?wù)器有時(shí)需要主動(dòng)發(fā)送數(shù)據(jù)到client端。這顯然比較麻煩,原本模塊內(nèi)部的復(fù)雜性被擴(kuò)散到上層代碼。一點(diǎn)疏急就可能就導(dǎo)致資源泄漏或重復(fù)釋放,或者訪問已經(jīng)釋放的資源而發(fā)生內(nèi)存訪問異常,一旦這種bug出現(xiàn)將很難跟蹤調(diào)試。作為一個(gè)基礎(chǔ)模塊的編寫者, 設(shè)計(jì)時(shí)就要考慮這一點(diǎn),無論誰寫的代碼,好的結(jié)構(gòu)都可以起到強(qiáng)有力的約束作用,如果不是必要,我建議你不要用這種方式 。最后有一點(diǎn)需要注意的是,如果你沒有資源需要在IOCP處理發(fā)送/接收之外的地方訪問,你就不要去分配一個(gè)結(jié)構(gòu)體,以免增加額外的麻煩。
?
第二種方式自然更不會(huì)遇到重復(fù)資源釋放的問題(你可以在任何地方關(guān)閉連接,并釋放相關(guān)資源),因?yàn)槟汜尫刨Y源時(shí),同時(shí)刪除hash表中的連接上下文,所以在釋放之前應(yīng)該檢查連接上下文是否存在,如果不存在,則表示資源已被釋放。需要注意的是對(duì)本次操作的發(fā)送/接收緩存應(yīng)該立刻釋放,同時(shí)這些緩存指針不必保存到上下文,而是綁定到相應(yīng)的OVERLAPPED。這種方式還有一個(gè)優(yōu)點(diǎn),可以跟蹤所有連接(例如逐一掃描所有連接,處理一些如心跳包之類的事情)。當(dāng)然你可能擔(dān)心hash表畢竟對(duì)速度有影響,我們舉個(gè)例子,你的IOCP一秒種需要處理10萬個(gè)IO,則需要10萬次hash操作,我想說的是 10萬次/一秒的hash其實(shí)對(duì)現(xiàn)在的CPU是非常輕松的,不用擔(dān)心它成為瓶頸。這種方式相對(duì)實(shí)現(xiàn)非常簡單,出現(xiàn)bug也相對(duì)易于跟蹤,對(duì)于服務(wù)器的設(shè)計(jì)而言,我一直固執(zhí)的堅(jiān)持,穩(wěn)定性始終是第一的。