Socket編程中,阻塞與非阻塞的區別

  阻塞:通常的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 的模式大概分爲這麼幾種:
一、阻塞式的,Socket操做都須要將線程掛起,等待內核完成後才能返回。
如: 調用connect=>進入內核=>Syn包=〉服務器返回SYN ACK 包=〉connect返回。
=〉ACK包發往服務器。
但通常來講,阻塞和非阻塞對於recv來講意義更大。
當在阻塞式的Socket上調用recv時,若是這時網絡棧上沒有數據給你接收,那麼這時線程將
會掛起,直到有報文給你接收才返回。
這樣就形成你的應用程序在企圖接收數據時候,而網絡棧上沒有數據的時候就會被鎖住。
有什麼辦法解決這個問題呢? 咱們來介紹IO
二、 IO複用, 就是在企圖讀寫數據的時候先詢問下是否可讀寫,若是不能,能夠去幹別的事情,不會形成死鎖。
可是假如咱們有大量的鏈接須要去頻繁的查詢可讀寫狀態,每次查詢都會和內核交互。這樣會形成
效率低下。再介紹一種
三、 重疊IO. 就是一次查詢多個Socket的狀態。不用去來來回回的遍歷。
另外,
  在windows socket api 中還有一種消息機制,就是把Socket狀態通知到窗口。而後用消息去處理。
  對於重疊IO, 在windows上還有完成端口模型,他和重疊端口相比,不但能捕捉到IO事件, 並且內核已經替你完成了Socket IO, 好比read事件, 在內核通知你的時候,他已經幫你讀好數據了,並放在你指定的緩存中(這裏是指在用戶態下,事先爲每一個Socket分配的內存)。
爲何有這麼多socket模式呢? 哪一個更好呢?
爲何有,我不知道,多是出於需求吧,
說說哪一個更好?
  孤立的來講,其實沒有哪一個更好? 只有哪一個更適合你的應用應用環境。
如: 阻塞式的比較簡單,方便,穩定。適合比較簡單的客戶端程序。
IO複用我認爲它適合SocketIO操做比較少的狀況。
重疊IO就適合高性能的服務器的開發,另外完成端口是windows上比較公認的高性能服務器的網絡開發模型。固然, windows 的IOCP也有個壞處,就是須要大量的內存,應爲前面說了他須要事先指定緩存。不太高性能的 服務器,通常都不用windows平臺。
windows的消息模型就比較適合有UI的應用程序。
固然, 有些模型的選擇上可能還有我的愛好的因素,
如, 我可能不喜歡用消息模型,
我不喜歡被動的被通知, 而喜歡主動的去查詢。windows

相關文章
相關標籤/搜索