recv函数返回值总结

来源:互联网 发布:室内分布设计软件 编辑:程序博客网 时间:2024/06/02 05:05

函数原型: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));