非阻塞EWOULDBLOCK的问题

magic_feng 2010-11-15 11:02:57
服务器使用select模型,当客户端有连接后,用if (FD_ISSET(clientSocket,&read_set))判断是否有读操作,结果客户端没发任何数据,但这个判断一直为true,使用recv接收数据,返回值一直小于0,并且是EWOULDBLOCK,请问这个问题是否正常?如果不正常如何处理?
...全文
1096 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
testing2007 2010-12-02
  • 打赏
  • 举报
回复
maoxing63570
对于产生的现象,不知道是不是这样,可以试一下:
在accept以后,客户端会给服务器发送一个ACK确认连接信号,这个时候,你在下面的调用中,select就会变成可读被判断为true,即使你客户端没有发送任何数据。
在代码中为了避免这个错误现象,在select之前需要对read,write之前对检视的套接字IO集合进行初始话,也就是在accept之后,select之前。
代码修改为:
fd_set fd_read,fd_write;
while(true)
{
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);

FD_SET(AcceptSock,&fd_read);
FD_SET(AcceptSock,&fd_write);
testing2007 2010-12-02
  • 打赏
  • 举报
回复
“因为如果select告诉我们连接已经就绪,accept就不应该被阻塞;”

lishengkai:你的回复,看不明白啊,代码里面不是先建立了连接(accept)之后才使用select的嘛?

能不能解析的更加清楚点啊?

对于这个问题我也挺感兴趣的,我也继续调查调查,同时也希望有高手解答!
lishengkai 2010-11-19
  • 打赏
  • 举报
回复
当一个已完成的连接准备好被accept的时候,select会把监听socket标记为可读;因此,如果用select等待外来的连接时,应该不需要把监听socket设置为非阻塞模式,因为如果select告诉我们连接已经就绪,accept就不应该被阻塞;
不过这样做的时候有一个BUG:当客户端在跟服务器建立连接之后发送了一个RST包,这个时候accept就会阻塞,直到有下一个已完成的连接准备好被accept为止.
struct linger的l_onoff标志设为1,l_linger设为0.这个时候,如果关闭TCP连接时,会先在socket上发送一个RST包;这个时候会出现下面的问题:
A:select向服务器返回监听socket可读,但是服务器要在一段时间之后才能调用accept;
B:在服务器从select返回和调用accept之前,收到从客户发送过来的RST;
C:这个已经完成的连接被从队列中删除,我们假设没有其它已完成的连接存在;
D:服务器调用accept,但是由于没有其它已完成的连接存在,因而服务器被阻塞了;
注意,服务器会被一直阻塞在accept调用上,直到另外一个客户建立一个连接为止;但是如果一直没有其它客户建立连接,那么服务器将仍然一直被阻塞在accept调用上,不处理任何其他已就绪的socket;
解决这个问题的办法是:
A:如果使用select来获知何时有链接已就绪可以accept时,总是把监听socket设置为费阻塞模式,并且
B:在后面的accept调用中忽略以下错误:EWOULDBLOCK(源自Berkeley的实现在客户放弃连接时出现的错误)、ECONNABORTED(Posix.1g的实现在客户放弃连接时出现的错误)、EPROTO(SVR4的实现在客户放弃连接时出现的错误)和EINTR(如果信号被捕获).

照着上面的试试看能不能解决问题
maoxing63570 2010-11-16
  • 打赏
  • 举报
回复

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

BOOL InitSocket()
{
WSADATA wsaData;
WORD wVersionRequested;
int err=0;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0)
{
cout<<"Could not find a usage WinSock DLL"<<GetLastError()<<endl;
return false;
}

if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
cout<<"Could not find a usage WinSock DLL"<<GetLastError()<<endl;
WSACleanup();
return false;
}
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
if(!InitSocket())
return -1;

SOCKET ListenSock;
SOCKET AcceptSock;
SOCKADDR_IN InterAddr;
ListenSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
InterAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
InterAddr.sin_family=AF_INET;
InterAddr.sin_port=htons(8000);

if(ListenSock==INVALID_SOCKET)
{
cout<<"A error ocured while build a socket"<<GetLastError()<<endl;
closesocket(ListenSock);
WSACleanup();
return -1;
}

if(bind(ListenSock,(sockaddr *)&InterAddr,sizeof(sockaddr))==SOCKET_ERROR)
{
cout<<"A error ocured while binding a socket"<<GetLastError()<<endl;
closesocket(ListenSock);
WSACleanup();
return -1;
}

if(listen(ListenSock,5)==SOCKET_ERROR)
{
cout<<"A error ocured while listening on a socket"<<GetLastError()<<endl;
closesocket(ListenSock);
WSACleanup();
return -1;
}
char sendbuf[512]={'\0'};
char recvbuf[512]={'\0'};
fd_set fd_read,fd_write;
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
TIMEVAL timeout;
timeout.tv_sec=13;
timeout.tv_usec=0;
int ret=0;
int bytes_recv;
AcceptSock=accept(ListenSock,NULL,NULL);
if(AcceptSock==INVALID_SOCKET)
{
cout<<"A error ocured while accept connect request from client"<<GetLastError()<<endl;
closesocket(ListenSock);
closesocket(AcceptSock);
WSACleanup();
return -1;
}
while(true)
{
FD_SET(AcceptSock,&fd_read);
FD_SET(AcceptSock,&fd_write);
ret=select(NULL,&fd_read,&fd_write,NULL,&timeout);
if(ret==SOCKET_ERROR)
continue;
if(ret>0)
{
if(FD_ISSET(AcceptSock,&fd_read))
{
if((bytes_recv=recv(AcceptSock,recvbuf,sizeof(recvbuf),NULL))==SOCKET_ERROR)
{
cout<<"A error ocured while receive data from client"<<GetLastError()<<endl;
closesocket(AcceptSock);
closesocket(ListenSock);
WSACleanup();
return -1;
}
else
cout<<recvbuf<<endl;
}
else
{
if(FD_ISSET(AcceptSock,&fd_write))
{
gets(sendbuf);
if(send(AcceptSock,sendbuf,sizeof(sendbuf),NULL)==SOCKET_ERROR)
{
cout<<"A error ocured while send data to client"<<GetLastError()<<endl;
closesocket(AcceptSock);
closesocket(ListenSock);
WSACleanup();
return -1;
}
}
}

}
}
return 0;
}


今早才写的,代码写的不是太好,一起研究下,嘻嘻
bestilyq 2010-11-16
  • 打赏
  • 举报
回复
把这部分代码贴出来看看吧

4,356

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧