Blocking/Non-Blocking VS Sync/Async VS Overlapped
[轉載請注明:出自cnblogs,作者:byeyear,Email:east3@163.com]
[2012.10.08: 完善文章內容]
本文主要討論幾個在網絡編程中經常被討論但也經常被誤解的概念:
阻塞(Blocking),非阻塞(Non-Blocking),同步(Sync),異步(Async),重疊(Overlapped)。
首先要明確的是,只有那些會導致發生“數據傳輸”的函數(accept,connect,send,recv等)才存在這些概念;像bind、listen這些不會引發“數據傳輸”的函數,是不存在“阻塞非阻塞”或“同步異步”這樣的問題的。
其次一個比較重要的問題是,Non-Blocking和Async不是一回事。在一些論壇文章和關于網絡編程的書中,將這兩者等同,這是不正確的。
1. Blocking和Non-Blocking
Blocking:只有在函數所請求的操作完成后,函數才會返回。例如,accept會等到連接隊列非空才返回;recv會等到數據緩沖區中有數據后才返回。因此,blocking的意思是,操作若不能完成函數就不返回。
Non-Blocking:如果操作無法立即完成,send/recv這樣的函數將以失敗返回,函數所請求的操作不會得到執行。同時WSAGetLastError函數將返回WSAEWOULDBLOCK。例如,如果緩沖區中沒有數據,recv會立即返回。在Non-Blocing模式下,程序可以通過一個循環不停調用recv,直到有數據可用。
2. Sync、Async和Overlapped
Sync:App層的函數調用和OS底層的動作是順序的。例如,App調用recv -> OS執行recv -> 執行完成 -> 函數返回。
Async:App層的函數調用和OS底層的動作是非順序的。例如,App以填充好的Overlapped結構調用WSARecv,即使無數據可讀,函數也會立即返回,但OS底層仍然會繼續執接收數據的工作,并在有數據可用時以event、callback或completion port的形式通知App。而Overlapped和Async實際上是一個概念。之所以叫“Overlapped”,是指多次函數調用可以重疊進行。例如,你可以在有數據可讀前多次調用WSARecv。如果一個Async IO不能立即完成,函數將以失敗返回,同時你WSAGetLastError將返回WSA_IO_PENDING。但是,底層的操作將繼續執行。你的程序將在稍后得到通知。
3. Blocking/Non-Blocking通過ioctlsocket設定,設定完成后,后續的send/recv將遵循最經一次的ioctlsocket設置。
4. overlapped和兩方面有關:一是通過WSASocket創建socket時是否設定了overlapped標記(socket默認設置overlapped),二是WSASend/WSARecv調用是否提供overlapped結構。
??? 4.1 如果WSASocket沒有設定overlapped,那么這個socket將是sync的且不可改變,WSASend/WSARecv的行為和send/recv類似;
??? 4.2 如果WSASocket設定了overlapped,那么有三種情況:
??????? 4.2.1 使用send/recv。這兩個函數不支持overlapped,所以函數行為是sync的;
??????? 4.2.2 使用WSASend/WSARecv,但不提供overlapped結構。函數行為同樣是sync的;
??????? 4.2.3 使用WSASend/WSARecv,并且提供overlapped結構。函數行為時Async的。App將在數據可用時得到通知。
??? 從上文可以看出,即使為socket設定了overlapped attribute,仍然可以對該socket使用非overlapped函數調用。換句話說,ASync/overlapped僅是socket所具備的一個“功能”,你可以用,也可以不用。這和Non-Blocking是不同的,在那里,一旦設定了Non-Blocking,函數調用必定是Non-Blocking的。
綜上,我們可以得到socket I/O操作的幾種方法:
a) Blocking,Sync:這個是最簡單的。連接建立后,App調用recv或send收發數據。
b) Non-Blocking,Sync:使用ioctlsocket將指定socket設置為Non-Blocking。在ioctlsocket之后,若數據不可用,recv或send將返回WSAEWOULDBLOCK。
c) Blocking,Async:若無數據可用,send或recv函數將Blocking。WSARecv和WSASend將立即返回,并在有數據可用時通知App。
d) Non-Blocing,Async:在無數據可用的情況下,send/recv將返回WSAEWOULDBLOCK,WSARecv/WSASend將返回SOCKET_ERROR。區別在于,send/recv除了立即返回以外不會有別的效果,而WSARecv和WSASend雖然也是立即返回,但它們所請求的操作將由OS繼續執行,直到有數據可用后通知App。
寶書《Windows網絡編程》中所述的幾種Model,實際上就是Blocking/Non-Blocking和Sync/Async的不同組合。
a) 阻塞模式:Blocking + Sync
b) 非阻塞模式:Non-Blocking + Sync。App通過不停調用send/recv獲取數據。
c) select模式:Blocking + Non-Sync。和a)的區別在于,阻塞在select上而不是send/recv上。select保證后續的send/recv操作不會阻塞,看起來好像是Non-Blocking一樣——但實質上仍然是Blocking模式。
d) WSAEventSelect/WSAAsyncSelect:Non-Blocking + Sync。這兩個函數會自動將socket設置為Non-Blocking(MSDN如是說)。和b)的區別在于由OS負責在數據可用時發出Message或SetEvent,不需要App自己Polling。
e) Overlapped:Blocking + ASync。在這種情況下,一般不會使用send/recv函數而是使用WSASend或WSARecv,所以Blocking不會成為問題。如果你不小心在這種model下使用了send/recv,那么這兩個函數仍然會在無數據可用的情況下blocking住。
?參考文檔:http://support.microsoft.com/kb/181611/en-us?fr=1
總結
以上是生活随笔為你收集整理的Blocking/Non-Blocking VS Sync/Async VS Overlapped的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        