网络编程之epoll怎么判断数据读取完毕?

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

之前写过几篇关于网络编程的文章,c++之网络编程c++之网络编程–文件传输QT之TCP网络编程QT之网络编程-文件传输,可以参考一下。

epoll怎么判断数据读取完毕,这里有两种做法:

1、针对TCP,调用recv方法,根据recv的返回值。如果返回值小于我们设定的recv buff的大小,那么就认为接收完毕。
2、TCP、UDP都适用,将socket设为NOBLOCK状态(使用fcntl函数),然后select该socket可读的时候,使用read/recv函数读取数据。当返回值为-1,并且errno是EAGAIN或EWOULDBLOCK的时候,表示数据读取完毕。

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

一、fcntl函数
详细可见Linux下socket设置为非阻塞方式和fcntl系统调用
功能描述:根据文件描述符来操作文件的特性。
用法:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
参数:
fd:文件描述符。
cmd:操作命令。
arg:供命令使用的参数。
lock:同上。
有以下操作命令(cmd)可供使用
1) F_DUPFD :复制文件描述词 。
2) FD_CLOEXEC :设置close-on-exec标志。如果FD_CLOEXEC位是0,执行execve的过程中,文件保持打开。反之则关闭。
3) F_GETFD :读取文件描述词标志。
4) F_SETFD :设置文件描述词标志。
5) F_GETFL :读取文件状态标志。
6) F_SETFL :设置文件状态标志。
其中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_NOCTTY 和 O_TRUNC不受影响,
可以更改的标志有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。
7) F_GETLK, F_SETLK 和 F_SETLKW :获取,释放或测试记录锁

用以下方法将socket设置为非阻塞方式

int flags = fcntl(socket, F_GETFL, 0); 
fcntl(socket, F_SETFL, flags | O_NONBLOCK);

将非阻塞的设置回阻塞可以用

int flags = fcntl(socket, F_GETFL, 0); 
fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

二、errno错误码
详细可见Linux errno详解
Linux中系统调用的错误都存储于 errno中,errno由操作系统维护,存储就近发生的错误,即下一次的错误码会覆盖掉上一次的错误。

关于errno的其中两个宏定义:

#define EAGAIN      11  /* Try again */
#define EWOULDBLOCK EAGAIN  /* Operation would block */

三、实例判断数据读取完毕。

1、将socket设置成非阻塞

void  setnonblocking( int  sock)
{
     int  opts;
    opts = fcntl(sock,F_GETFL);
     if (opts < 0 )
    {
        perror( " fcntl(sock,GETFL) " );
        exit( 1 );
    }
    opts  =  opts | O_NONBLOCK;
     if (fcntl(sock,F_SETFL,opts) < 0 )
    {
        perror( " fcntl(sock,SETFL,opts) " );
        exit( 1 );
    }
}

2、判断错误码errno

while(1)
{
	iResult = recv(sockfd, buf, RECV_BUF_SIZE, 0);
	if (iResult == -1) 
	{
		if (errno == EAGAIN || errno == EWOULDBLOCK) 
		{
			printf(" recv finish detected, quit.../n ");
			break;
		}
	}
	printf(" Received %d bytes/n ", iResult);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值