关于非阻塞的recv的时候返回的处理

版权声明:本文为博主学习相关知识所搜集的资料,版权归原博主所有。

注意recv()如果读到数据为0,那么就表示文件结束了,如果在读的过程中遇到了中断那么会返回-1,同时置errno为EINTR。

因此判断recv的条件:
    如果read返回<=0
       如果==0
           表示文件结束, 处理
       如果<0 && errno==EINTR
           表示中断,处理
       否则,出错

我们举个例子:

int safe_tcp_recv (int sockfd, void *buf, int bufsize)
{
int cur_len;
recv_again:
cur_len = recv (sockfd, buf, bufsize, 0);
//closed by client
if (cur_len == 0)
{
TRACE_LOG ("connection closed by peer, fd=%d", sockfd);
return 0;
}
else if (cur_len == -1)
{
if (errno == EINTR)
goto recv_again;
else
ERROR_LOG ("recv error, fd=%d, errno=%d %m", sockfd, errno);
}
return cur_len;
}
或者
int safe_tcp_recv_n (int sockfd, void *buf, int total)
{
int recv_bytes, cur_len;
for (recv_bytes = 0; recv_bytes < total; recv_bytes += cur_len)
{
cur_len = recv (sockfd, buf + recv_bytes, total - recv_bytes, 0);
//closed by client
if (cur_len == 0) //正常关闭
{
TRACE_LOG ("connection closed by peer, fd=%d", sockfd);
return -1;
}
else if (cur_len == -1)
{
if (errno == EINTR)//还需要在读
cur_len = 0;
else if (errno == EAGAIN)
{
TRACE_LOG ("recv %d bytes from fd=%d", recv_bytes, sockfd);
return recv_bytes;
}
else
{
ERROR_RETURN (("recv tcp packet error, fd=%d, %m", sockfd), -1);
}
}
}
return recv_bytes;
}

但是write()如果写入的数据为0,那么就表示出错,也就是无法写入了,而如果在写的过程中遇到了中断,那么write()会返回-1,同时置errno为EINTR。
 因此判断write是否成功时,条件是write返回的结果是否<=0
 
int safe_tcp_send_n (int sockfd, const void *buf, int total)
{
int send_bytes, cur_len;
for (send_bytes = 0; send_bytes < total; send_bytes += cur_len)
{
cur_len = send (sockfd, buf + send_bytes, total - send_bytes, 0);
//closed by client
if (cur_len == 0)
{
TRACE_LOG ("send tcp packet error, fd=%d, %m", sockfd);
return -1;
}
else if (cur_len == -1)
{
if (errno == EINTR)
cur_len = 0;
else if (errno == EAGAIN)
{
return send_bytes;
}
else
{
TRACE_LOG ("send tcp packet error, fd=%d, %m", sockfd);
return -1;
}
}
}
//TRACE_LOG ("send: fd=%d, len=%d", sockfd, send_bytes);
return send_bytes;
}

首先我们看看recv的返回值:
 EAGAIN、EWOULDBLOCK、EINTR与非阻塞 长连接

EWOULDBLOCK用于非阻塞模式,不需要重新读或者写
EINTR指操作被中断唤醒,需要重新读/写
在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中)。
从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以 O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返 回,read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试。重新读数据,其实这个也就是说明了一点,网络报还没有发完结束呢,还需要继续读,除非返回的是大于0的值,就代表的是读完了,返回正常读到的网络报的长度。
又例如,当一个系统调用(比如fork)因为没有足够的资源(比如虚拟内存)而执行失败,返回EAGAIN提示其再调用一次(也许下次就能成功)。
Linux - 非阻塞socket编程处理EAGAIN错误
在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这是什么意思?
这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。 对非阻塞socket而言,EAGAIN不是一种错误。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。
另外,如果出现EINTR即errno为4,错误描述Interrupted system call,操作也应该继续。
最后,如果recv的返回值为0,那表明连接已经断开,我们的接收操作也应该结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Python中的socket.recv()可以设置为非阻塞模式,这意味着当没有数据可用时,它不会一直等待数据到达。相反,它会立即返回一个错误或一个空字节串。这对于需要同时处理多个连接的服务器非常有用,因为它可以避免一个连接的阻塞影响其他连接的处理。要将socket设置为非阻塞模式,可以使用socket.setblocking(False)方法。 ### 回答2: Python中的Socket是一种面向流的网络通信方式,它可以通过"recv()"方法来接收客户端发送的数据。而阻塞式的"recv()"方法会一直等待客户端发送数据才返回,这可能会造成程序卡死等问题,所以我们可以采用非阻塞式来接收数据。 首先,我们需要将socket设置为非阻塞模式,即"sock.setblocking(False)"。然后,我们可以调用"recv()"方法。如果没有接收到数据,会抛出"No data available"异常,我们可以通过try-catch语句来避免程序崩溃。如果接收到了数据,"recv()"方法会立即返回。接收到的数据可能不是一个完整的数据包,需要我们自己进行缓存和拼接,直到接收到一个完整的数据包为止。可以通过定义一个缓存区来实现这个功能。 同时,我们可以使用"select"模块来监听socket的可读事件,一旦socket可读,我们便可以使用非阻塞式的"recv()"方法来接收数据,确保程序不会阻塞。 这样就可以通过非阻塞式的方式来接收客户端发送的数据,保证了程序的正常运行。 ### 回答3: Python的Socket库提供了处理套接字通信的常用功能。其中,recv()函数是常见的用于接收数据的函数。通常情况下,recv()函数是阻塞的,也就是说如果没有接收到数据,该函数会一直等待,直到数据到来或者超时。 在某些情况下,我们希望recv()函数不会阻塞程序执行,而是在没有接收到数据时立即返回。这时,我们可以使用非阻塞模式来调用recv()函数。 首先,我们需要将套接字设置为非阻塞模式,可以通过以下代码实现: ```python import socket # 创建一个套接字,并设置为非阻塞模式 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setblocking(False) ``` 接下来,我们可以在调用recv()函数之前,使用try-except语句来捕获异常,从而实现非阻塞接收数据: ```python try: data = sock.recv(buffer_size) except socket.error as e: if e.errno == errno.EWOULDBLOCK: # 没有数据可接收 pass else: # 其他错误 print(e) ``` 在这段代码中,我们使用try-except语句来捕获socket.error异常,如果该异常的错误代码为errno.EWOULDBLOCK,则表示当前没有数据可以接收。如果有数据可以接收,则data变量将包含接收到的数据。 需要注意的是,在非阻塞模式下,recv()函数可能会接收到部分数据,因此我们需要在循环中多次调用该函数,直到接收到完整的数据。 总之,Python Socket库提供了一种非阻塞模式来实现接收数据的方式,给予开发者更多的灵活性和控制力,但也需要对错误码有一定的了解,才能正确地处理异常情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值