send和recv函數解析(轉)

    http://blog.chinaunix.net/uid-23208702-id-131258.htmlhtml

每個除send外的Socket函數在執 行的最開始總要先等待套接字的發送緩衝中的數據被協議傳送完畢才能繼續,若是在等待時出現網絡錯誤,那麼該Socket函數就返回 SOCKET_ERROR服務器

    

1. send函數網絡

int send( SOCKET s, const char FAR *buf, int len, int flags );  socket

不管是客戶端仍是服務器端應用程序都用send函數來向TCP鏈接的另外一端發送數據。函數

客戶端程序通常用send函數向服務器發送請求,而服務器則一般用send函數來向客戶程序發送應答。ui

該函數的:spa

第一個參數指定發送端套接字描述符;.net

第二個參數指明一個存放應用程序要發送數據的緩衝區;unix

第三個參數指明實際要發送的數據的字節數;指針

第四個參數通常置0。

這裏只描述同步Socket的send函數的執行流程。當調用該函數時,send先比較待發送數據的長度len和套接字s的發送緩衝的長度,若是len大於s的發送緩衝區的長度,該函數返回SOCKET_ERROR;若是len小於或者等於s的發送緩衝區的長度,那麼send先檢查協議 是否正在發送s的發送緩衝中的數據,若是是就等待協議把數據發送完,若是協議尚未開始發送s的發送緩衝中的數據或者s的發送緩衝中沒有數據,那麼 send就比較s的發送緩衝區的剩餘空間和len,若是len大於剩餘空間大小send就一直等待協議把s的發送緩衝中的數據發送完,若是len小於剩餘 空間大小send就僅僅把buf中的數據copy到剩餘空間裏(注意並非send把s的發送緩衝中的數據傳到鏈接的另外一端的,而是協議傳的,send僅僅是把buf中的數據copy到s的發送緩衝區的剩餘空間裏)。若是send函數copy數據成功,就返回實際copy的字節數,若是send在copy數據時出現錯誤,那麼send就返回SOCKET_ERROR;若是send在等待協議傳送數據時網絡斷開的話,那麼send函數也返回SOCKET_ERROR。

要注意send函數把buf中的數據成功copy到s的發送緩衝的剩餘空間裏後它就返回了,可是此時這些數據並不必定立刻被傳到鏈接的另外一端。若是協議在後續的傳送過程當中出現網絡錯誤的話,那麼下一個Socket函數就會返回SOCKET_ERROR。(每個除send外的Socket函數在執 行的最開始總要先等待套接字的發送緩衝中的數據被協議傳送完畢才能繼續,若是在等待時出現網絡錯誤,那麼該Socket函數就返回 SOCKET_ERROR)

注意:在Unix系統下,若是send在等待協議傳送數據時網絡斷開的話,調用send的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。

Send函數的返回值有三類:

(1)返回值=0:

(2)返回值<0:發送失敗,錯誤緣由存於全局變量errno中

(3)返回值>0:表示發送的字節數(其實是拷貝到發送緩衝中的字節數)

 

錯誤代碼:

EBADF 參數s 非合法的socket處理代碼。
EFAULT 參數中有一指針指向沒法存取的內存空間
ENOTSOCK 參數s爲一文件描述詞,非socket。
EINTR 被信號所中斷。
EAGAIN 此操做會令進程阻斷,但參數s的socket爲不可阻斷。
ENOBUFS 系統的緩衝內存不足
ENOMEM 核心內存不足
EINVAL 傳給系統調用的參數不正確。

 

2.  recv函數

int recv( SOCKET s,     char FAR *buf,      int len,     int flags     );   

不管是客戶端仍是服務器端應用程序都用recv函數從TCP鏈接的另外一端接收數據。

該函數的:

第一個參數指定接收端套接字描述符;

第二個參數指明一個緩衝區,該緩衝區用來存放recv函數接收到的數據;

第三個參數指明buf的長度;

第四個參數通常置0。

這裏只描述同步Socket的recv函數的執行流程。當應用程序調用recv函數時,recv先等待s的發送緩衝 中的數據被協議傳送完畢,若是協議在傳送s的發送緩衝中的數據時出現網絡錯誤,那麼recv函數返回SOCKET_ERROR,若是s的發送緩衝中沒有數 據或者數據被協議成功發送完畢後,recv先檢查套接字s的接收緩衝區,若是s接收緩衝區中沒有數據或者協議正在接收數據,那麼recv就一直等待,只到 協議把數據接收完畢。當協議把數據接收完畢,recv函數就把s的接收緩衝中的數據copy到buf中(注意協議接收到的數據可能大於buf的長度,因此 在這種狀況下要調用幾回recv函數才能把s的接收緩衝中的數據copy完。recv函數僅僅是copy數據,真正的接收數據是協議來完成的),recv函數返回其實際copy的字節數。若是recv在copy時出錯,那麼它返回SOCKET_ERROR;若是recv函數在等待協議接收數據時網絡中斷了,那麼它返回0。

注意:在Unix系統下,若是recv函數在等待協議接收數據時網絡斷開了,那麼調用recv的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。

 

默認狀況下socket是阻塞的。

阻塞與非阻塞recv返回值沒有區別,都是:

<0 出錯

=0 對方調用了close API來關閉鏈接

>0 接收到的數據大小,

 

特別地:返回值<0時而且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的狀況下認爲鏈接是正常的,繼續接收。

只是阻塞模式下recv會一直阻塞直到接收到數據,非阻塞模式下若是沒有數據就會返回,不會阻塞着讀,所以須要循環讀取)。

 

返回說明:   

(1)成功執行時,返回接收到的字節數。

(2)若另外一端已關閉鏈接則返回0,這種關閉是對方主動且正常的關閉

(3)失敗返回-1,errno被設爲如下的某個值   

EAGAIN:套接字已標記爲非阻塞,而接收操做被阻塞或者接收超時

EBADF:sock不是有效的描述詞

ECONNREFUSE:遠程主機阻絕網絡鏈接

EFAULT:內存空間訪問出錯

EINTR:操做被信號中斷

EINVAL:參數無效

ENOMEM:內存不足

ENOTCONN:與面向鏈接關聯的套接字還沒有被鏈接上

ENOTSOCK:sock索引的不是套接字

相關文章
相關標籤/搜索