IOCP中的socket錯誤和資源釋放處理方法

2021-04-06 19:02:18 字數 1626 閱讀 9610

本文出處:

前言: 

錯誤處理和socket釋放, 是iocp程式設計中的一大難點. 本文試圖就iocp設計中經常遇到的這個難題展開論述並尋找其解決方案, 事實上, 文中所述的解決方式不僅僅適用於iocp, 它同樣適用於epoll等多種伺服器程式設計的網路模型中, 前提是: 領會這種處理方式的實質.

正文:在使用iocp開發時, 大家經常遇到的乙個難題是與socket相關的緩衝區釋放不當帶來的錯誤, 這種錯誤通常是由於多次對同乙個指標執行了delete操作引起的. 比如, 當在執行wsasend或wsarecv返回了非pending的錯誤資訊時, 我們就要對此錯誤進行處理, 通常情況下, 我們會想到執行這兩步操作:

a. 釋放此次操作使用的緩衝區資料(如果不釋放可能造成記憶體洩漏);

b. 關閉當前操作所使用的socket.

而另一方面, 我們可能也會在get函式(getqueuedcompletionstatus)的處理中, 當get函式返回值為false時也作這兩步相同的操作.  此時, 就會造成對同一緩衝區的重複釋放, 問題由此產生.

解決的方法, 可以有這幾種:

1. 對資料緩衝區使用引用計數機制;

2. 在clientsock的物件設計機制上使釋放操作線性化.

關於這兩種方法, 任何一種如果要詳細說清, 可能篇幅都會比較長, 筆者並無耐心和精力將每乙個細節都一一道來, 在此僅選第2種方案的關鍵步驟和核心思想來與大家分享.

由前面對問題的描述可以看出, 造成多次釋放的原因可能是在執行收發操作和get函式返回值為false時, 我們重複執行了釋放操作. 很自然地, 我們會想到,  能不能把這兩次釋放合併成一次釋放,  這樣不就沒問題了嗎?  yes,  這個思路是沒問題的.  但要想讓這個思路能變成現實,  需要在設計機制上對這個思路進行一定的支援.

首先,  我們假設, 是在get函式返回時統一進行相應的釋放和關閉操作.

如果在執行wsasend操作時, 發生了非pending錯誤(io操作正在進行中), 而此時我們如果不釋放資源, 那至少得讓iocp在get返回時得知這個錯誤和發生錯誤時的緩衝區指標. 通知iocp的方式, 是使用post函式(postqueuedcompletionstatus)向iocp拋乙個特殊標誌的訊息, 這個特殊標誌可以通過get函式的第二個引數, 即: 傳送位元組數來表示, 可以選擇任何乙個不可能出現的值, 比如任何乙個跟它的初始值不相等的負數.  當然, 如果你通過單句柄資料或單io資料來傳遞也是可以的. 而發生錯誤的這個緩衝區指標, 我們是必須要通過單句柄資料或單io資料來傳遞的. 但是, 從整個緩衝區的管理機制上來說, 我不推薦這樣的離散緩衝區機制, 我的建議是: 把收發緩衝區或資料佇列與相應的clientsocket物件相繫結, 釋放操作寫在該物件的析構函式裡, 這樣當釋放clientsocket物件時就釋放了這些緩衝區.

ok, 這樣一來, 在get函式裡, 有三種情況需要執行釋放邏輯:

1. get的返回值為false;

2. 傳送位元組數為0;

3. 接收到剛才我們post的那個錯誤型別訊息.

把釋放操作全放在get函式裡以後, 對釋放操作的處理, 就比較統一了. 當然, 為了實現真正的線性化和元子化, 在釋放操作的最終執行邏輯上, 還需要對釋放**加鎖以實現執行緒互斥(當然, 這是在你開了多個工作者執行緒的情況下).

IOCP中的socket錯誤和資源釋放處理方法

錯誤處理和socket釋放,是iocp程式設計中的一大難點.本文試圖就iocp設計中經常遇到的這個難題展開論述並尋找其解決方案,事實上,文中所述的解決方式不僅僅適用於iocp,它同樣適用於epoll等多種伺服器程式設計的網路模型中,前提是 領會這種處理方式的實質.正文 在使用iocp開發時,大家經常...

關於Socket和IOCP的一些值得注意的地方

關於socket和iocp的一些值得注意的地方 關於socket和iocp的一些值得注意的地方收藏 iocp是一整套高效能的io操作非同步模型,可以用在檔案操作也可以用在網路socket操作上面。當用在網路socket上時,在伺服器端主要配合aceeptex wsasend wsasendto來使用...

關於Socket和IOCP的一些值得注意的地方

iocp是一整套高效能的io操作非同步模型,可以用在檔案操作也可以用在網路socket操作上面。當用在網路socket上時,在伺服器端主要配合aceeptex wsasend wsasendto來使用,在客戶機端主要配合connectex wsarecv和wsarecvfrom來使用。這幾天用ioc...