1. 程式人生 > >recv函式返回值總結

recv函式返回值總結

函式原型:int recv( SOCKET s, char *buf, int  len, int flags)

功能:不論是客戶還是伺服器應用程式都用recv函式從TCP連線的另一端接收資料

引數一:指定接收端套接字描述符

引數二:指明一個緩衝區,該緩衝區用來存放recv函式接收到的資料

引數三:指明buf的長度

引數四 :一般置為0

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

 >  0  成功接收資料大小

 =  0  另外一端關閉了套接字

 = -1     錯誤,需要獲取錯誤碼errno(win下是通過WSAGetLastError())

 errno被設為以下的某個值:

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

               對非阻塞socket而言,EAGAIN不是一種錯誤。在VxWorks和Windows上,EAGAIN的名字叫EWOULDBLOCK。


EBADF:sock不是有效的描述詞

ECONNREFUSE:遠端主機阻絕網路連線

EFAULT:記憶體空間訪問出錯
EINTR:操作被訊號中斷
EINVAL:引數無效
ENOMEM:記憶體不足
ENOTCONN:與面向連線關聯的套接字尚未被連線上
ENOTSOCK:sock索引的不是套接字 


返回值<0時並且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的情況下認為連線是正常的,繼續接收。
只是阻塞模式下recv會阻塞著接收資料,非阻塞模式下如果沒有資料會返回,不會阻塞著讀,因此需要迴圈讀取)。

while(1)
{
    cnt = (int)recv(m_socket, pBuf,RECVSIZE, 0);
    if( cnt >0 )
    {
        //正常處理資料
    }
    else
   {
         if((cnt<0) &&(errno == EAGAIN||errno == EWOULDBLOCK||errno == EINTR)) 

         //這幾種錯誤碼,認為連線是正常的,繼續接收

        {
            continue;//繼續接收資料
        }
        break;//跳出接收迴圈
    }
}

首先阻塞接收的recv有時候會返回0,這僅在對端已經關閉TCP連線時才會發生。

而當拔掉裝置網線的時候,recv並不會發生變化,仍然阻塞,如果在這個拔網線階段,socket被關掉了,後果可能就是recv永久的阻塞了。所以一般對於阻塞的socket都會用setsockopt來設定recv超時,當超時時間到達後,recv會返回錯誤,也就是-1,而此時的錯誤碼是EAGAIN或者EWOULDBLOCK,POSIX.1-2001上允許兩個任意一個出現都行,所以建議在判斷錯誤碼上兩個都寫上。

      如果socket是被對方用linger為0的形式關掉,也就是直接發RST的方式關閉的時候,recv也會返回錯誤,錯誤碼是ENOENT

      還有一種經常在程式碼中常見的錯誤碼,那就是EINTER,意思是系統在接收的時候因為收到其他中斷訊號而被迫返回,不算socket故障,應該繼續接收。但是這種情況非常難再現,我嘗試過一邊一直在不停的發訊號,一邊用recv接收資料,也沒有出現過。這種異常錯誤我附近只有一個朋友在用write的時候見到過一次,但是總是會有概率出現的,所以作為完善的程式必須對此錯誤進行特殊處理。

一般設定超時的阻塞recv常用的方法都如下

Linux環境下,須如下定義:struct timeval timeout = {3,0}; 
//設定傳送超時
setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));

//設定接收超時
setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
--------------------- 
作者:AncientCastle 
來源:CSDN 
原文:https://blog.csdn.net/hq354974212/article/details/76077635 
版權宣告:本文為博主原創文章,轉載請附上博文連結!