Linux网络编程 -- select/epoll得知socket有数据可读,如何判断数据全部被读取完毕?

补充一点:只有在使用epoll ET(Edge Trigger)模式的时候,才需要关注数据是否读取完毕了。使用select或者epoll的LT模式,其实根本不用关注数据是否读完了,select/epoll检测到有数据可读去读就OK了。

 

这里有两种做法:

 

1. 针对TCP,调用recv方法,根据recv方法的返回值,如果返回值小于我们指定的recv buffer的大小,则认为数据已经全部接收完成。在Linux epoll的manual中,也有类似的描述:

 

For stream-oriented files (e.g., pipe, FIFO, stream socket), the condition that the read/write I/O space is exhausted can also be detected  by  checking the  amount  of data read from / written to the target file descriptor.  For example, if you call read(2) by asking to read a certain amount of data and read(2) returns a lower number of bytes, you can be sure of having exhausted the read I/O space for the file descriptor.  The same is true when  writing using write(2).  (Avoid this latter technique if you cannot guarantee that the monitored file descriptor always refers to a stream-oriented file.)

 

2. TCP和UDP都适用。将socket设成NONBLOCK(使用fcntl函数),然后select到该socket可读之后,使用read/recv来读取数据。当函数返回-1,同时errno是EAGAIN或EWOULDBLOCK的时候,表示数据已经全部读取完毕。

 

实验结论:

 

第一种方法是错误的。简单来说,如果发送了4K字节,recv的时候使用一个2K的buffer,那么,recv两次之后就再也没有数据可以recv了,此时recv就会block。永远不会出现recv返回值小于2K的情况(注:recv/read返回0表示对端socket已经关闭)。

 

所以推荐使用第二种方法,第二种方法正确而且对TCP和UDP都管用。事实上,不论什么平台编写网络程序,我认为都应该使用select+NONBLOCK socket的方式。这样可以保证你的程序至少不会在recv/send/accept/connect这些操作上发生block从而将整个网络服务都停下来。不好的地方就是不太利于Debug,如果是block的socket,那么GDB一跟就能知道阻塞在什么地方了。。。

 

其实所谓读取完毕指的是kernel中该socket对应的input data queue中的数据全部被读取了出来,从而该socket在kernel中被设置成了unreadable的状态。所以如果比如在局域网内,sender一直不断发送数据,则select到recv socket可读之后,我们就可以一直不停的读取到数据。所以,如果一个网络程序接收端想一次把数据全部接收完并且将所有接收到的数据都保存在内存中的话,就需要考虑到这种情况,避免占用过多的内存。

 

下面是测试代码,代码中client读取了4K了之后就退出了,因为sender每次发送4K,所以client select到一次readable之后,就只会读取到4K。

Client.c:

#include  < stdio.h >
#include 
< stdlib.h >
#include 
< errno.h >
#include 
< string .h >
#include 
< netdb.h >
#include 
< sys / types.h >
#include 
< netinet /
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当在Linux系统中使用socket读取数据时,如果返回-115错误,通常表示接收缓冲区空间不足的错误。 当你使用socket函数创建套接字并进行数据传输时,内核会为每个套接字分配接收缓冲区,用于存储接收到的数据。如果接收缓冲区已满,而继续接收数据,则会导致缓冲区溢出,数据丢失或覆盖。 -115错误常见于非阻塞模式的套接字操作。在非阻塞模式下,读操作会立即返回,并不会等待数据准备好。而当接收缓冲区为空时,读操作尝试读取数据会返回-115错误。 如果你遇到这个错误,你可以通过以下方法解决: 1. 增加接收缓冲区大小:通过修改套接字选项,可以增加接收缓冲区的大小。可以使用setsockopt函数来设置SO_RCVBUF选项,将缓冲区大小增加到你需要的大小。 2. 使用非阻塞模式的循环读取:可以使用非阻塞模式,并在循环中进行读取操作。当返回-115错误时,可以继续循环等待数据准备好,并进行读取。 3. 使用selectepoll函数进行异步IO操作:这些函数可以用于监视套接字文件描述符,当有数据可读时再进行读取操作,避免出现接收缓冲区空间不足的错误。 总之,linux socket读取数据返回-115错误通常是由于接收缓冲区空间不足引起的。通过增大接收缓冲区大小、使用非阻塞模式的循环读取或使用异步IO操作等方法,可以解决这个问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值