send/recv与socket
send函數
不論是客戶端還是服務器端應用程序都用send函數來向TCP連接的另一端發送數據??蛻舳顺绦蛞话阌胹end函數向服務器發送請求,而服務器則通常用send函數來向客戶程序發送應答。
當調用send函數時,send先比較待發送數據的長度len和套接字s的發送緩沖區,如果len大于發送緩沖區的長度,該函數返回錯誤SOCKET_ERROR;如果len <= s的發送緩沖區,那么send先檢查協議是否正在發送s的發送緩沖區中的數據,如果是就等待協議把數據發送完畢,如果協議還沒有開始發送s的發送緩沖區中的數據或者s的發送緩沖區中沒有數據,那么send就比較s的發送緩沖區的剩余空間和len,如果len > 剩余空間 send就一直等待協議把s的發送緩沖區中的數據發送完,如果len < 剩余空間 send就僅僅把buf中的數據copy到剩余空間里(send僅僅是把buf中的數據copy到s的發送緩沖區中,至于把數據傳送到另一端是協議傳的不是send)。如果send函數copy數據成功,就返回實際copy的字節數,如果send在copy數據時出現錯誤或者在等待協議傳送數據時網絡斷開,那么send函數也返回SOCKET_ERROR。
要注意send函數把buf中的數據成功copy到s的發送緩沖區的剩余空間里,send函數就返回了,但是此時這些數據并不一定馬上被傳送到連接的另一端。如果協議在后續的傳送過程中出現網絡錯誤的話,那么下一個socket函數就會返回SOCKET_ERROR。但是注意的是:每一個除send以外的socket函數在執行的最開始總要等待套接字的發送緩沖區中的數據被協議傳送完畢才能繼續,如果在等待時出現網絡錯誤,那么該socket函數就返回SOCKET_ERROR。
注意:在Unix系統之下,如果send在等待協議傳送數據時網絡斷開,調用send的進程會接受到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。
錯誤代碼:
EBADF?參數s?非合法的socket處理代碼。
EFAULT?參數中有一指針指向無法存取的內存空間
ENOTSOCK?參數s為一文件描述詞,非socket。
EINTR?被信號所中斷。
EAGAIN?此操作會令進程阻斷,但參數s的socket為不可阻斷。
ENOBUFS?系統的緩沖內存不足
ENOMEM?核心內存不足
EINVAL?傳給系統調用的參數不正確。
recv函數
當調用recv函數時,recv函數先等待s的發送緩沖區中的數據都被協議傳送完畢,如果協議在傳送數據時出現了網絡錯誤,那么recv函數返回SOCKET_ERROR,如果s的發送緩沖區中沒有數據或者協議成功發送完畢后,recv函數先檢查s的接受緩沖區,如果s接收緩沖區中沒有數據或者正在接收數據,那么recv函數久一直等待直到協議把數據接收完畢。當協議把數據接收完畢,recv函數就把s的接收緩沖區中的數據copy到buf中(注意協議接收到的數據可能大于buf的長度,所以在這種情況下要調用幾次recv函數才能把s的接收緩沖區中的數據copy完畢。recv函數僅僅是拷貝數據,真正的接收數據是協議來完成的),recv函數返回其實際copy的字節數。如果recv函數在copy時出錯,返回SOCKET_ERROR,如果recv函數在等待協議接收數據時網絡中斷了,那么recv函數返回0。
注意:在Unix系統下,如果recv函數在等待協議接收數據時網絡斷開了,那么調用recv的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。
返回值說明
阻塞模式下recv會一直阻塞直到接收到數據,非阻塞模式下如果沒有數據就會返回,不會阻塞著讀,因此需要循環讀取)。
返回說明:???
(1)成功執行時,返回接收到的字節數。
(2)若另一端已關閉連接則返回0,這種關閉是對方主動且正常的關閉
(3)失敗返回-1,errno被設為以下的某個值???
特別地:返回值<0時并且(errno?==?EINTR?||?errno?==?EWOULDBLOCK?||?errno?==?EAGAIN)的情況下認為連接是正常的,繼續接收。
EAGAIN:套接字已標記為非阻塞,而接收操作被阻塞或者接收超時
EBADF:sock不是有效的描述詞
ECONNREFUSE:遠程主機阻絕網絡連接
EFAULT:內存空間訪問出錯
EINTR:操作被信號中斷
EINVAL:參數無效
ENOMEM:內存不足
ENOTCONN:與面向連接關聯的套接字尚未被連接上
ENOTSOCK:sock索引的不是套接字
socket緩沖區
默認情況下socket是阻塞的。
send函數并不是直接將數據傳輸到網絡中,而是負責將數據寫入輸出緩沖區,數據從輸出緩沖區發送到目標主機是由TCP協議完成的。數據寫入到輸出緩沖區之后,send函數就可以返回了,數據是否發送出去,是否發送成功,何時到達目標主機,都不由它負責了,而是由協議負責。
recv函數也是一樣的,它并不是直接從網絡中獲取數據,而是從輸入緩沖區中讀取數據。
輸入輸出緩沖區,系統會為每個socket都單獨分配,并且是在socket創建的時候自動生成的。一般來說,默認的輸入輸出緩沖區大小為8K。套接字關閉的時候,輸出緩沖區的數據不會丟失,會由協議發送到另一方;而輸入緩沖區的數據則會丟失。
Socket數據發送與接收問題
數據的發送和接收是獨立的,并不是發送方執行一次send,接收方就執行以此recv。recv函數不管發送幾次,都會從輸入緩沖區盡可能多的獲取數據。如果發送方發送了多次信息,接收方沒來得及進行recv,則數據堆積在輸入緩沖區中,取數據的時候會都取出來。換句話說,recv并不能判斷數據包的結束位置。
send函數:
在數據進行發送的時候,需要先檢查輸出緩沖區的可用空間大小,如果可用空間大小小于要發送的數據長度,則send會被阻塞,直到緩沖區中的數據被發送到目標主機,有了足夠的空間之后,send函數才會將數據寫入輸出緩沖區。
TCP協議正在將數據發送到網絡上的時候,輸出緩沖區會被鎖定(生產者消費者問題),不允許寫入,send函數會被阻塞,直到數據發送完,輸出緩沖區解鎖,此時send才能將數據寫入到輸出緩沖區。
要寫入的數據大于輸出緩沖區的最大長度的時候,要分多次寫入,直到所有數據都被寫到緩沖區之后,send函數才會返回。
recv函數:
函數先檢查輸入緩沖區,如果輸入緩沖區中有數據,讀取出緩沖區中的數據,否則的話,recv函數會被阻塞,等待網絡上傳來數據。如果讀取的數據長度小于輸出緩沖區中的數據長度,沒法一次性將所有數據讀出來,需要多次執行recv函數,才能將數據讀取完畢。
?
參考:
https://blog.csdn.net/u010270148/article/details/53605339
https://www.cnblogs.com/sunziying/p/6501045.html
https://www.cnblogs.com/Berryxiong/p/6547510.html
https://www.cnblogs.com/msb-/articles/6042413.html
https://blog.csdn.net/u010871058/article/details/76147082
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的send/recv与socket的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: brew彻底卸载mysql
- 下一篇: opencv 二值化图像 像素统计 co