關於IOCP,某些地方就是不讓人徹底舒服(WSASend重疊post數據)


開門見山,直接就事論事。

 

假如有這么一個基於IOCP模型的Server,這個Server提供的所有服務中有這么一種服務……文件下載,我們再假設Server端存有一個20G的文件,客戶端這時發送一個請求到服務端來,客戶端要求下載這個20G的文件,由此可能引發一系列讓人頭疼的問題(不談TransmitFile,我們談WSASend)

 

先給出一段偽代碼,這段代碼肯定是有問題的,如下:

[html]  view plain copy
  1. //在某個線程里,我們開始向某個客戶端瘋狂發送這20G的文件了  
  2. while(true)  
  3. {  
  4.     char *data=new char[PER_SEND_DATA_LEN];  
  5.   
  6.     ::ReadFile(...,data,PER_SEND_DATA_LEN,&len,...);  
  7.   
  8.     io_data.wsabuf.buf=data;  
  9.     io_data.wsabuf.len=len;  
  10.     ::WSASend(...,&io_data.wsabuf,...);  
  11.   
  12.     delete []data;  
  13.       
  14.     if(len<PER_SEND_DATA_LEN) break;  
  15. }  

這樣無節操的發送基本上會得到一個WSAENOBUFS(緩沖區不足)錯誤,這個不是什么大問題,不會影響到IOCP底層模塊的設計,值得注意的是下面一個問題——數據發送不完全

 

接着上面的例子繼續思考下去。

假如其中一個WSASend投遞長度為PER_SEND_DATA_LEN的數據,而GetQueuedCompletionStatus(...,&BytesTransferred,...)返回結果卻表明這次發送沒有進行完全,BytesTransferred<PER_SEND_DATA_LEN,而后續的WSASend函數正源源不斷地投遞新的請求,即使我們在Get函數返回后,再次投遞WSASend請求補發剩余數據,也無法保證這樣的補發可以趕在其他WSASend的前面。

 

如果以上推測成立的話,那么數據將不可避免的出現亂序。

 

當然,這只是一種擔心,實際上到目前為止,本人還沒有遇到過這種情況,個人認為:這種情況應該不會發生,一定是哪些地方還沒有搞透徹,否則重疊的意義何在?不過,網上擔心這種情況的人也不少,以下是提出這些問題的鏈接(不保證都是原創):

http://blog.csdn.net/skiing_886/article/details/8044186

http://bbs.eyuyan.com/read.php?tid=306324

 

上面兩個鏈接中,其中一個是篇博客,博客中明言WSASend帶重疊結構投遞請求時,不會出現數據發送不完全的情況,本人比較容易相信別人,於是我就信了。就算那篇博客說錯了,本人也還是覺得數據亂序的情況不會發生。

 

下面,本人想就這個問題,結合IOCP的完成隊列說一些自己的猜想(完全是猜想,假設WSASend所投遞的數據有可能發送不完全)。

首先,IOCP維護着一個的隊列,這個隊列沒有好妖魔化的,就是一個先進先出的數據結構,效率很高就是了。問題是,是不是我們每次調用WSASend都將導致一次入列,而每次GetQueuedCompletionStatus函數返回都會導致一次出列呢?

 

結合上面的那個下載文件的例子,細細一想,如果每次GetQueuedCompletionStatus返回都要出列一次數據包的話,那一旦出現數據發送不完全的情況,即使我們再次調用WSASend補發,那也只能將數據附加到完成隊列的頭部,亂序是必然的。

 

但是,換個思維,這種問題連我都能想到,微軟那么多高智商人才難道都是吃干飯的嗎?

 

所以,我認為,當數據發送不完全的時候,GetQueuedCompletionStatus應該是不會出列數據的,而可能是占着茅坑不拉屎,等待WSASend再次補發未完成的數據發送,而這個WSASend肯定不會導致數據數據重新入列,而只是給一個繼續發送的信號。

 

如果是我的,我肯定會這樣設計,否則,那就只能采取保險的做法,WSASend不重疊投遞,一次投遞之后需要等待Get函數返回再決定是要投遞一個補發的WSASend請求還是投遞下一個完整數據包的WSASend請求。這種做法雖然保險,但這突出了IOCP的巨大缺陷,正如我前面所說的,重疊的意義何在?WSASend還有必要帶着個OVERLLAPED結構嗎?

 

所以,我認為,這種情況的數據亂序不可能發生,不用擔心,嗯,不擔心……

 

說到最后,再順便提一下STL。STL的出列操作是Pop,它是不帶任何返回值的出列,要想知道出列了什么數據必須在Pop之前調用front方法。有人強烈鄙視這種設計,認為這種設計極其別扭。要知道,STL的設計者必然是高手,設計成這樣自然有理由,隊列這種東西,要想通用的話,最好還是要把‘看’和‘取’分開,STL的設計是綜合考慮的結果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM