阻塞:一般的I/O操作可以在新建的流中運用.在服務器回應前它等待客戶端發送一個空白的行.當會話結束時,服務器關閉流和客戶端socket.如果在隊列中沒有請示將會出現什麼情況呢?那個方法將會等待一個的到來.這個行為叫阻塞.accept()方法將會阻塞服務器線程直到一個呼叫到來.當5個連接處理完閉之後,服務器退出.任何的在隊列中的呼叫將會被取消.
非阻塞:非阻塞套接字是指執行此套接字的網絡調用時,不管是否執行成功,都立即返回。比如調用recv()函數讀取網絡緩沖區中數據,不管是否讀到數據都立即返回,而不會一直掛在此函數調用上。在實際Windows網絡通信軟件開發中,異步非阻塞套接字是用的最多的。平常所說的C/S(客戶端/服務器)結構的軟件就是異步非阻塞模式的。
具體機制就是上面所說的,簡明扼要的來說可以打個比方:
你有數個同學來訪 <---> 有若干數據需要收取
你時不時的去門口看看,沒有看到你同學的話就回客廳等待,看到同學就接到客廳來 <---> 非阻塞模式,無論收到數據與否都返回
你一直在門口等著你同學,接到後才回客廳 <---> 阻塞模式,接收到數據後才返回
使用阻塞怎麼了?會帶來什麼後果?在什麼情況之下?對性能有影響麼?
套接字有兩種模式,阻塞模式與非阻塞模式。默認創建的為阻塞模式.
在blocking model 下:
套接字在IO時阻塞應用程序,就是說控制權不會返回給應用程序,也就是說程序執行到此代碼時會卡住。分兩種情況,1.send函數時,只有把要發送的數據下傳至TCP層,send這句代碼才繼續向下執行,此時可確認自己的數據已經在網絡上傳輸了2.recv時,只有收到一定數據給應用程序緩沖區時,recv這行代碼才會向下執行。如果不想這樣做,可以使用多線程,或者選用其他網絡IO模型。一般在做服務器程序時,不會使用阻塞套接字,性能低,數據吞吐率也不高。優點是此種模型編寫難度較低,可以用來做入門的學習之用。
非阻塞套接字,IO會馬上返回.但在send時,如果SOCKET緩沖區已滿,會返回錯誤,使用WSAGetLastError會得到錯誤碼為WSAEWOULDBLOCK,意思是說在一個非阻塞的套接字上,請求沒有完成。recv時如果SOCKET緩沖區沒有可以讀的數據,也會返回WSAEWOULDBLOCK.
Socket 的模式大概分為這麼幾種:
1、阻塞式的,Socket操作都需要將線程掛起,等待內核完成後才能返回。
如: 調用connect=>進入內核=>Syn包=〉服務器返回SYN ACK 包=〉connect返回。
=〉ACK包發往服務器。
但一般來說,阻塞和非阻塞對於recv來說意義更大。
當在阻塞式的Socket上調用recv時,如果這時網絡棧上沒有數據給你接收,那麼這時線程將
會掛起,直到有報文給你接收才返回。
這樣就造成你的應用程序在企圖接收數據時候,而網絡棧上沒有數據的時候就會被鎖住。
有什麼辦法解決這個問題呢? 我們來介紹IO
2、 IO復用, 就是在企圖讀寫數據的時候先詢問下是否可讀寫,如果不能,可以去干別的事情,不會造成死鎖。
但是假如我們有大量的連接需要去頻繁的查詢可讀寫狀態,每次查詢都會和內核交互。這樣會造成
效率低下。再介紹一種
3、 重疊IO. 就是一次查詢多個Socket的狀態。不用去來來回回的遍歷。
另外,
在windows socket api 中還有一種消息機制,就是把Socket狀態通知到窗口。然後用消息去處理。
對於重疊IO, 在windows上還有完成端口模型,他和重疊端口相比,不但能捕捉到IO事件, 而且內核已經替你完成了Socket IO, 比如read事件, 在內核通知你的時候,他已經幫你讀好數據了,並放在你指定的緩存中(這裡是指在用戶態下,事先為每個Socket分配的內存)。
為什麼有這麼多socket模式呢? 哪個更好呢?
為什麼有,我不知道,可能是出於需求吧,
說說哪個更好?
孤立的來說,其實沒有哪個更好? 只有哪個更適合你的應用應用環境。
如: 阻塞式的比較簡單,方便,穩定。適合比較簡單的客戶端程序。
IO復用我認為它適合SocketIO操作比較少的情況。
重疊IO就適合高性能的服務器的開發,另外完成端口是windows上比較公認的高性能服務器的網絡開發模型。當然, windows 的IOCP也有個壞處,就是需要大量的內存,應為前面說了他需要事先指定緩存。不過高性能的 服務器,一般都不用windows平台。
windows的消息模型就比較適合有UI的應用程序。
當然, 有些模型的選擇上可能還有個人愛好的因素,
如, 我可能不喜歡用消息模型,
我不喜歡被動的被通知, 而喜歡主動的去查詢。