epoll 中使用et模式,recv获取数据不全问题。
本帖最后由 dragonsea 于 2013-09-09 16:02:48 编辑 epoll中使用ET模式,使用recv获取数据。存在以下问题“
1.已经使用while循环取,但是提交8052字节的数据时,获取不全,一般能获取2000多字节。但是在recv方法下面调用sleep(1) 就能获取完整数据。请问这是为什么?如何修改代码能获取全部数据?
2.在调用recv方法前,检测errno的值为11(EAGAIN),调用recv后,无论是否能正常获取数据,哪怕recv返回值大于0,errno也是11 .也就是 EAGEIN. 为什么? errno的值不会因为最近一次recv成功调用,而改变值吗?
3.会不会出现这种情况,客户端发了个很大的包。在传输的时候,可能需要分包传输。当第一个包到达的时候,epoll触发了EPOLLIN事件,此时进行recv获取数据,得到第一个包。但是没有达到指定的长度,再次recv获取,这个时候第二个包还未到达。结果获取的长度为 -1 .
代码如下:
//读取数据
void recvData(int fd)
{
memset(buffer, 0, BUFFER_LEN);
int len;
int data_len = 0;
memset(buffer, 0, BUFFER_LEN);
cout << "before recv errno: " << errno << endl;
while (1)
{
len = recv(fd, &buffer[data_len], 10, MSG_DONTWAIT);//MSG_PEEK
if (len > 0)
{
data_len += len;
}
cout << "\n=============\n len:" << len << "\n strlen(buffer):" << strlen(buffer) << "\n" << "errno:" << errno << "\n" << buffer << endl;
//sleep(1); //把注释去掉后,就可以正常读取了
if (len == -1)
{
if (errno == EAGAIN)
{
break;
}else if (errno == EINTR)
{
continue;
}
}
}
}
输出结果如下:
before recv errno: 11
=============
len:10
strlen(buffer):10
errno:11
TRACE Card
=============
len:10
strlen(buffer):20
errno:11
TRACE Cardura Kaufen
=============
len:10
strlen(buffer):30
errno:11
TRACE Cardura Kaufen | Für Sc
=============
len:10
strlen(buffer):40
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deu
=============
len:10
strlen(buffer):50
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deutschland,
=============
len:10
strlen(buffer):60
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deutschland, Osterreich
=============
len:10
strlen(buffer):70
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deutschland, Osterreich, Holland
=============
len:10
strlen(buffer):80
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deutschland, Osterreich, Holland
[url=http
=============
len:10
strlen(buffer):90
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deutschland, Osterreich, Holland
[url=http://health-
=============
len:10
strlen(buffer):100
errno:11
TRACE Cardura Kaufen | Für Schweiz, Deutschland, Osterreich, Holland
[url=http://health-seller.net epoll
[解决办法]
抓包工具看看吧! 确认是否都完全发送过来了
有没有丢包!
对于网路方面的,请学会用wireshark抓包工具
[解决办法]
方向偏了,
ET只支持non-block模式工作,这种模式本身就不保证recv一次读完,而是每次缓冲区处于可读状态时就触发用户事件了,这个通常是知道包长度之后手写while来确保读到完整数据包的。non-block正确处理EAGAIN错误的方式就是继续读...
至于什么时候触发fd可读事件这个还不是太了解,猜测的结论是当前读缓冲区的数据盖过低水位了吧,明天把文档拉出来再瞧瞧(这台机子没书签)。
顺便坐等达人详解。
[解决办法]
ET,就是沿触发模式。读写都是EGAIN结束,并且不能丢失这个沿。否则就是电瓶触发模式。性能,有点差。多还是少,还是看你的操控能力。