IOCP的一些總結

2021-06-14 02:52:38 字數 3857 閱讀 1337

1:在iocp中投遞wsasend返回wsa_io_pending的時候,表示非同步投遞已經成功,但是稍後傳送才會完成。這其中涉及到了三個緩衝區。

網絡卡緩衝區,tcp/ip層緩衝區,程式緩衝區。

情況一:呼叫wsasend傳送正確的時候(即立即返回,且沒有錯誤),tcp/ip將資料從程式緩衝區中拷貝到tcp/ip層緩衝區中,然後不鎖定該程式緩衝區,由上層程式自己處理。tcp/ip層緩衝區在網路合適的時候,將其資料拷貝到網絡卡緩衝區,進行真正的傳送。

情況二:呼叫wsasend傳送錯誤,但是錯誤碼是wsa_io_pending的時候,表示此時tcp/ip層緩衝區已滿,暫時沒有剩餘的空間將程式緩衝區的資料拷貝出來,這時系統將鎖定使用者的程式緩衝區,按照書上說的wsasend指定的緩衝區將會被鎖定到系統的非分頁記憶體中。直到tcp/ip層緩衝區有空餘的地方來接受拷貝我們的程式緩衝區資料才拷貝走,並將給iocp乙個完成訊息。

情況三:呼叫wsasend傳送錯誤,但是錯誤碼不是wsa_io_pending,此時應該是傳送錯誤,應該釋放該socket對應的所有資源。

2:在iocp中投遞wsarecv的時候,情況相似。

情況一:呼叫wsarecv正確,tcp/ip將資料從tcp/ip層緩衝區拷貝到緩衝區,然後由我們的程式自行處理了。清除tcp/ip層緩衝區資料。

情況二:呼叫wsarecv錯誤,但是返回值是wsa_io_pending,此時是因為tcp/ip層緩衝區中沒有資料可取,系統將會鎖定我們投遞的wsarecv的buffer,直到tcp/ip層緩衝區中有新的資料到來。

情況三:呼叫wsarecv錯誤,錯誤值不是wsa_io_pending,此時是接收出錯,應該釋放該socket對應的所有資源。

在以上情況中有幾個非常要注意的事情:

系統鎖定非分頁記憶體的時候,最小的鎖定大小是4k(當然,這個取決於您系統的設定,也可以設定小一些,在登錄檔裡面可以改,當然我想這些數值微軟應該比我們更知道什麼合適了),所以當我們投遞了很多wsarecv或者wsasend的時候,不管我們投遞的buffer有多大(0除外),系統在出現io_pengding的時候,都會鎖定我們4k的記憶體。這也就是經常有開發者出現wsanobuf的情況原因了。

我們在解決這個問題的時候,要針對wsasend和wsarecv做處理

1:投遞wsarecv的時候,可以採用乙個巧妙的設計,先投遞0大小buf的wsarecv,如果返回,表示有資料可以接收,我們開啟真正的recv將資料從tcp/ip層緩衝區取出來,直到wsa_io_pengding.

2:對投遞的wsarecv以及wsasend進行計數統計,如果超過了我們預定義的值,就不進行wsasend或者wsarecv投遞了。

3:現在我們應該就可以明白為什麼wsasend會返回小於我們投遞的buffer空間資料值了,是因為tcp/ip層緩衝區小於我們要傳送的緩衝區,tcp/ip只會拷貝他剩餘可被copy的緩衝區大小的資料走,然後給我們的wsasend的已傳送緩衝區設定為移走的大小,下一次投遞的時候,如果tcp/ip層還未被傳送,將返回wsa_io_pengding。

4:在很多地方有提到,可以關閉tcp/ip層緩衝區,可以提高一些效率和效能,這個從上面的分析來看,有這個可能,要實際的網路情況去實際分析了。

***************===

關於資料報在應用層亂序問題就不多說了(iocp荒廢了tcp在傳輸層辛辛苦苦保證的有序)。

這無關緊要,因為iocp要管理上千個socket,每個socket的讀請求、寫請求分別保證序列即可。

**********===

關於getqueuedcompletionstatus的返回值判斷:

我給超時值傳的是0,直接測試,無須等待。

這裡我們關心這幾個值:

第二個引數所傳回的byte值

第三個引數所傳回的complete key值 ——per handle data

系統設定的error值。

在超時情況下,byte值返回0,per handle data值是-1,per io data為null

1.如果返回false

one : iocp控制代碼在外部被關閉。

wsagetlasterror返回6(無效控制代碼),byte值返回0,per handle data值是-1,per io data為null

two: 我們主動close乙個socket控制代碼,或者cancelio(socket)(且此時有未決的操作)

wsagetlasterror返回995(由於執行緒退出或應用程式請求,已放棄 i/o 操作)

byte值為0,

per handle data與per io data正確傳回。

three:對端強退(且此時本地有未決的操作)

wsagetlasterror返回64(指定的網路名不再可用)

byte值為0,per handle data與per io data正確傳回

2.如果返回true【此時一定得到了你投遞的overlap結構】

one:  我接收到對端資料,然後準備再投遞接收請求;但此期間,對端關閉socket。

wsarecv返回錯誤碼10054:遠端主機強迫關閉了乙個現有的連線。

todo todo

從網上搜到乙個做法,感覺很不錯:

如果返回false, 那麼:如果overlap為空,那一定是發生了錯誤(注意:請排除timeout錯誤);

如果overlap不為空,有可能發生錯誤。不用管它,這裡直接投遞請求;如果有錯,wsarecv將返回錯誤。關閉連線即可。

**********==

關於closesocket操作:

structures, for example) referenced by the outstanding i/o requests until the i/o requests are indeed completed.

在iocp模式下,如果呼叫closesocket時有未決的pending   io,將導致socket被重置,所以有時會出現資料丟失。正統的解決方式是使用shutdown函式(指定sd_send標誌),注意這時可能有未完成的傳送pengding   io,所以你應該監測是否該連線的所有是否已完成(也許你要用乙個計數器來跟蹤這些pending   io),僅在所有send   pending   io完成後呼叫shutdown。

msdn推薦的優雅關閉socket:

call wsaasyncselect

to register for fd_close notification.

call shutdown with how=sd_send.

when fd_close received, call recv

until zero returned, or socket_error.

call closesocket.

對每個使用

acceptex

接受的連線套結字使用

setsockopt

設定so_update_accept_context

選項,這個選項原義是把

listen

套結字一些屬性(包括

socket

內部接受

/傳送快取大小等等)拷貝到新建立的套結字,卻可以使後續的

shutdown

呼叫成功。

/* so_update_accept_context is required for shutdown() to work fine*/

setsockopt( sockclient,

sol_socket,

so_update_accept_context,

(char*)&m_socklisten,

sizeof(m_socklisten) ) ;

如果是呼叫acceptex接收的連線 不設定該選項的話,隨後的shutdown呼叫

將返回失敗, wsagetlasterror() returns 10057 -- wsanotconn 

IOCP相關的一些總結

1 在iocp中投遞wsasend返回wsa io pending的時候,表示非同步投遞已經成功,但是稍後傳送才會完成。這其中涉及到了三個緩衝區。網絡卡緩衝區,tcp ip層緩衝區,程式緩衝區。情況一 呼叫wsasend傳送正確的時候 即立即返回,且沒有錯誤 tcp ip將資料從程式緩衝區中拷貝到t...

IOCP的一些心得

iocp的工作執行緒的個數一般設定為processors 2 2,這是綜合考慮了工作執行緒可能是等待 掛起 正在執行的狀態。如果你測試出更好的結果,以你的為標準。iocp的工作執行緒由系統排程和優化,不要去干預執行緒的排程,除非你自信能超越系統的排程。在遇到奇怪的問題時,可以嘗試減少iocp工作執行...

一些的總結

大學的教育模式是先教你原理,在教你怎麼用工具 而缺少樂趣,一般大牛 的思維模式都是這樣 先知道原理 在用工具 其實對於普通人來講,一般都是 知道原來還有這種利用方式?到 我要用工具來提高效率 廣用效率還不行 我要知道原理 誒好像現在工具滿足不了我的需要了,我要自己新增規則 新增的規則 以及滿足不了我...