之前写过一篇关于
Linux
下面采用
epoll
设计服务器应用程序的文章,时隔很久了,最近发现一个问题,是关于
read
函数读取报文时候问题,这里提出来。
epoll
并不像
windows
下的完成端口那样,可以通知用户此次事件(收数据或者发数据)的数据量有多少,因此在读取数据的时候就比较麻烦了,因为
epoll
通知你只是有新数据到达了,并不告诉你有多少,因此需要应用层运用循环不断的收数据,知道结束。结合下面的源代码进行分析一下。
while(m_RcvedLen < TotalSize) {
if((Rcv = read(m_sClient, m_Buffer, (TotalSize - m_RcvedLen))) < 0) {
if(EAGAIN == errno) {
break;
}
else {
perror("read fail");
close(m_sClient);
return -1;
}
}
else if(0 == Rcv){
close(m_sClient);
return -2;
}
else {
m_RcvedLen += Rcv;
}
}
if((Rcv = read(m_sClient, m_Buffer, (TotalSize - m_RcvedLen))) < 0) {
if(EAGAIN == errno) {
break;
}
else {
perror("read fail");
close(m_sClient);
return -1;
}
}
else if(0 == Rcv){
close(m_sClient);
return -2;
}
else {
m_RcvedLen += Rcv;
}
}
上面的代码是先读报头,后读报体的。原来是直接读,给
read
函数的第三个参数一个很大的值,知道
read
函数返回错误
EAGAIN
才表示没有数据可以读了,但是这样会出现一个问题,当客户端发送了数据之后就直接关闭
socket
,此时服务端第一包读取正常,这时循环继续读下一报,此时
read
函数不会返回
EAGAIN
,而是返回
0
,表示客户端已经关闭连接了。所以,在服务端读取的时候,一定要先读报文,从报文中获得此次报文的大小,然后依次来作为接收结束的判断条件。这样上层就可以根据
read
函数的返回值不同,区分出(
1
)还有报文可读(
2
)报文已经读完(
3
)对方关闭
socket
三种情况了。
本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/371899,如需转载请自行联系原作者