非阻塞io和阻塞io
在網路程式設計中對於乙個網路控制代碼會遇到阻塞io 和非阻塞io 的概念, 這裡對於這兩種socket 先做一下說明:
基本概念
阻塞io:socket 的阻塞模式意味著必須要做完io 操作(包括錯誤)才會返回。
非阻塞io:非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方式來判斷具體操作是否成功。(對於connect,accpet操作,通過select判斷,對於recv,recvfrom,send,sendto通過返回值+錯誤碼來判斷)
io模式設定
對於socket:
方法對於乙個socket是阻塞模式還是非阻塞模式的處理方法是用fcntl設定,用f_getfl獲取flags,用f_setfl設定flags|o_nonblock;同時,recv,send 時使用非阻塞的方式讀取和傳送訊息,即flags設定為msg_dontwait
實現fcntl函式可以將乙個socket控制代碼設定成非阻塞模式:
flags = fcntl(sockfd, f_getfl, 0);//獲取檔案的flags值。
fcntl(sockfd, f_setfl, flags | o_nonblock);//設定成非阻塞模式;
flags = fcntl(sockfd,f_getfl,0);
fcntl(sockfd,f_setfl,flags&~o_nonblock);//設定成阻塞模式;
並在接收和傳送資料時:
將recv, send 函式的最後有乙個flag 引數設定成msg_dontwait
recv(sockfd, buff, buff_size,msg_dontwait);//非阻塞模式的訊息傳送
send(scokfd, buff, buff_size, msg_dontwait);//非阻塞模式的訊息接受
對於普通檔案:
對於檔案的阻塞模式還是非阻塞模式:
方法1、open時,使用o_nonblock;
方法2、fcntl設定,使用f_setfl,flags|o_nonblock;
對於訊息佇列
對於訊息佇列訊息的傳送與接受:
//非阻塞 msgsnd(sockfd,msgbuf,msgsize(不包含型別大小),ipc_nowait)
//阻塞 msgrcv(scokfd,msgbuf,msgsize(**),msgtype,ipc_nowait);
阻塞與非阻塞讀的區別:
阻塞和非阻塞的區別在於沒有資料到達的時候是否立刻返回.
讀(read/recv/msgrcv):
讀的本質來說其實不能是讀,在實際中, 具體的接收資料不是由這些呼叫來進行,是由於系統底層自動完成的。read 也好,recv 也好只負責把資料從底層緩衝copy 到我們指定的位置.
對於讀來說(read, 或者recv):
阻塞情況下:
在阻塞條件下,read/recv/msgrcv的行為:
1、如果沒有發現資料在網路緩衝中會一直等待,
2、當發現有資料的時候會把資料讀到使用者指定的緩衝區,但是如果這個時候讀到的資料量比較少,比引數中指定的長度要小,read 並不會一直等待下去,而是立刻返回。
read 的原則:是資料在不超過指定的長度的時候有多少讀多少,沒有資料就會一直等待。
所以一般情況下:我們讀取資料都需要採用迴圈讀的方式讀取資料,因為一次read 完畢不能保證讀到我們需要長度的資料,
read 完一次需要判斷讀到的資料長度再決定是否還需要再次讀取。
非阻塞情況下:
在非阻塞的情況下,read 的行為:
1、如果發現沒有資料就直接返回,
2、如果發現有資料那麼也是採用有多少讀多少的進行處理.
所以:read 完一次需要判斷讀到的資料長度再決定是否還需要再次讀取。
對於讀而言:阻塞和非阻塞的區別在於沒有資料到達的時候是否立刻返回.
recv 中有乙個msg_waitall 的引數:
recv(sockfd, buff, buff_size, msg_waitall),
在正常情況下recv 是會等待直到讀取到buff_size 長度的資料,但是這裡的waitall 也只是盡量讀全,在有中斷的情況下recv 還是可能會被打斷,造成沒有讀完指定的buff_size的長度。
所以即使是採用recv + waitall 引數還是要考慮是否需要迴圈讀取的問題,在實驗中對於多數情況下recv (使用了msg_waitall)還是可以讀完buff_size,
所以相應的效能會比直接read 進行迴圈讀要好一些。
注意:使用msg_waitall時,sockfd必須處於阻塞模式下,否則不起作用。
所以msg_waitall不能和msg_nonblock同時使用。
要注意的是使用msg_waitall的時候,sockfd 必須是處於阻塞模式下,否則waitall不能起作用。
阻塞與非阻塞寫的區別:
寫(send/write/msgsnd):
寫的本質也不是進行傳送操作,而是把使用者態的資料copy 到系統底層去,然後再由系統進行傳送操作,send,write返回成功,只表示資料已經copy 到底層緩衝,而不表示資料已經發出,更不能表示對方埠已經接收到資料.
對於write(或者send)而言,
阻塞情況下:阻塞情況下,write會將資料傳送完。(不過可能被中斷)
在阻塞的情況下,是會一直等待,直到write 完,全部的資料再返回.這點行為上與讀操作有所不同。
原因:讀,究其原因主要是讀資料的時候我們並不知道對端到底有沒有資料,資料是在什麼時候結束傳送的,如果一直等待就可能會造成死迴圈,所以並沒有去進行這方面的處理;
寫,而對於write, 由於需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write 是可能被打斷嗎,造成write 一次只write 一部分資料, 所以write 的過程還是需要考慮迴圈write, 只不過多數情況下一次write 呼叫就可能成功.
非阻塞寫的情況下:
非阻塞寫的情況下,是採用可以寫多少就寫多少的策略.與讀不一樣的地方在於,有多少讀多少是由網路傳送的那一端是否有資料傳輸到為標準,但是對於可以寫多少是由本地的網路堵塞情況為標準的,在網路阻塞嚴重的時候,網路層沒有足夠的記憶體來進行寫操作,這時候就會出現寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到資料全部傳送完畢, 對於非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現write 到一部分的情況.
非阻塞IO和阻塞IO
非阻塞io 和阻塞io 在網路程式設計中對於乙個網路控制代碼會遇到阻塞io 和非阻塞io 的概念,這裡對於這兩種socket 先做一下說明 基本概念 阻塞io socket 的阻塞模式意味著必須要做完io 操作 包括錯誤 才會 返回。非阻塞io 非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他...
非阻塞IO 和阻塞IO
在網路程式設計中對於乙個網路控制代碼會遇到阻塞io 和非阻塞io 的概念,這裡對於這兩種socket 先做一下說明 基本概念 阻塞io socket 的阻塞模式意味著必須要做完io 操作 包括錯誤 才會 返回。非阻塞io 非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方 式來判斷具體操作是否...
非阻塞IO 和阻塞IO
非阻塞io 和阻塞io 在網路程式設計中對於乙個網路控制代碼會遇到阻塞io 和非阻塞io 的概念,這裡對於這兩種socket 先做一下說明 基本概念 阻塞io socket 的阻塞模式意味著必須要做完io 操作 包括錯誤 才會 返回。非阻塞io 非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他...