IO之阻塞与非阻塞比较
在網絡程序中遇到的一些問題進行了總結, 這里主要針對的是我們常用的TCP socket相關的總結, 可能會存在錯誤, 有任何問題歡迎大家提出.
對于網絡編程的更多詳細說明建議參考下面的書籍
《UNIX網絡編程》 《TCP/IP 詳解》 《Unix環境高級編程》
非阻塞IO和阻塞IO:
在網絡編程中對于一個網絡句柄會遇到阻塞IO和非阻塞IO的概念, 這里對于這兩種socket先做一下說明
基本概念:socket的阻塞模式意味著必須要做完IO操作(包括錯誤)才會返回。 非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方式來判斷具體操作是否成功。
設置:
一般對于一個socket是阻塞模式還是非阻塞模式有兩種方式 fcntl設置和recv,send系列的參數.
fcntl函數可以將一個socket句柄設置成非阻塞模式:
flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); 設置之后每次的對于sockfd的操作都是非阻塞的
recv, send函數的最后有一個flag參數可以設置成MSG_DONTWAIT臨時將sockfd設置為非阻塞模式,而無論原有是阻塞還是非阻塞。 recv(sockfd, buff, buff_size, MSG_DONTWAIT); send(scokfd, buff, buff_size, MSG_DONTWAIT);
區別:
讀:
讀本質來說其實不能是讀,在實際中, 具體的接收數據不是由這些調用來進行,是由于系統底層自動完成的,read也好,recv也好只負責把數據從底層緩沖copy到我們指定的位置. 對于讀來說(read, 或者 recv) ,在阻塞條件下如果沒有發現數據在網絡緩沖中會一直等待,當發現有數據的時候會把數據讀到用戶指定的緩沖區,但是如果這個時候讀到的數據量比較少,比參數中指定的長度要小,read并不會一直等待下去,而是立刻返回。read的原則是數據在不超過指定的長度的時候有多少讀多少,沒有數據就會一直等待。所以一般情況下我們讀取數據都需要采用循環讀的方式讀取數據,一次read完畢不能保證讀到我們需要長度的數據,read完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。在非阻塞的情況下,read的行為是如果發現沒有數據就直接返回,如果發現有數據那么也是采用有多少讀多少的進行處理.對于讀而言,阻塞和非阻塞的區別在于沒有數據到達的時候是否立刻返回.
recv中有一個MSG_WAITALL的參數 recv(sockfd, buff, buff_size, MSG_WAITALL), 在正常情況下 recv是會等待直到讀取到buff_size長度的數據,但是這里的WAITALL也只是盡量讀全,在有中斷的情況下recv還是可能會被打斷,造成沒有讀完指定的buff_size的長度。所以即使是采用recv + WAITALL參數還是要考慮是否需要循環讀取的問題,在實驗中對于多數情況下recv還是可以讀完buff_size,所以相應的性能會比直接read進行循環讀要好一些。不過要注意的是這個時候的sockfd必須是處于阻塞模式下,否則WAITALL不能起作用。
寫:
寫的本質也不是進行發送操作,而是把用戶態的數據copy到系統底層去,然后再由系統進行發送操作,返回成功只表示數據已經copy到底層緩沖,而不表示數據以及發出,更不能表示對端已經接收到數據.
對于write(或者send)而言,在阻塞的情況是會一直等待直到write完全部的數據再返回.這點行為上與讀操作有所不同,究其原因主要是讀數據的時候,通常剛開始我們并不知道要讀的數據的長度,而是在數據的頭部設置了一個長度,在讀完指定長度的頭部后,才知道整個要讀的數據長度。如果一開始就貿然設置一個要讀的數據長度,然后像阻塞的write那樣去等讀完,則很可能會造成死循環;而對于write, 由于需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write是可能被打斷造成write一次只write一部分數據, 所以write的過程還是需要考慮循環write, 只不過多數情況下一次write調用就可能成功。
非阻塞寫的情況下,是采用可以寫多少就寫多少的策略.與讀不一樣的地方在于,有多少讀多少是由網絡發送端是否有數據傳輸到本地內核緩存為準。但是對于可以寫多少是由本地的網絡堵塞情況為標準的,在網絡阻塞嚴重的時候,網絡層沒有足夠的內存來進行寫操作,這時候就會出現寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到數據全部發送完畢, 對于非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現write到一部分的情況.
二、同步和阻塞
阻塞與非阻塞是對同一個線程來說的,在某個時刻,線程要么處于阻塞,要么處于非阻塞。
阻塞是使用同步機制的結果,非阻塞則是使用異步機制的結果。
總結
以上是生活随笔為你收集整理的IO之阻塞与非阻塞比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RTP协议全解(H264码流和PS流)
- 下一篇: TCP之深入浅出send和recv