为什么select()总是在第一次超时后返回0
当我在Linux套接字程序上工作时,我对选择函数有一个问题。如果客户端在服务器配置的时间间隔内连接到服务器端,则select函数工作正常,如手册页所示。如果发生超时,select函数将永远返回0。当时,我调试了客户机,发现客户机已连接到服务器。但是select函数仍然返回0。我已经搜索了这个问题,但没有发现任何有用的。有人知道select为什么这样做吗?我的linux版本是RHEL5.4。谢谢你的帮助 代码如下所示为什么select()总是在第一次超时后返回0,c,linux,sockets,C,Linux,Sockets,当我在Linux套接字程序上工作时,我对选择函数有一个问题。如果客户端在服务器配置的时间间隔内连接到服务器端,则select函数工作正常,如手册页所示。如果发生超时,select函数将永远返回0。当时,我调试了客户机,发现客户机已连接到服务器。但是select函数仍然返回0。我已经搜索了这个问题,但没有发现任何有用的。有人知道select为什么这样做吗?我的linux版本是RHEL5.4。谢谢你的帮助 代码如下所示 static const int maxLog = 10000; int ma
static const int maxLog = 10000;
int main()
{
int servSock;
signal(SIGPIPE, SIG_IGN);
if((servSock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
printf("socket create fail\n");
exit(-1);
}
int val = 1;
if(setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))<0)
{
DieWithUserMessage("setsockopt error");
}
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(22000);
if(bind(servSock, (struct sockaddr *) &serverAddr,
sizeof(serverAddr)) < 0)
{
printf("socket bind fail\n");
exit(-1);
}
if(listen(servSock, maxLog) < 0)
{
printf("listen failed\n");
exit(-1);
}
fd_set read_set;
FD_ZERO(&read_set);
FD_SET(servSock, &read_set);
int maxfd1 = servSock + 1;
std::set<int> fd_readset;
for(;;){
struct timeval tv;
tv.tv_sec = 5;
int ret = select(maxfd1, &read_set, NULL, NULL, tv);
if(ret == 0)
continue;
if(ret < 0)
DieWithUserMessage("select error");
if(FD_ISSET(servSock, &read_set))
{
struct sockaddr_in clntAddr;
socklen_t clntAddrlen = sizeof(clntAddr);
int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrlen);
if(clntSock < 0)
{
printf("accept failed()");
exit(-1);
}
maxfd1 = 1 + (servSock>=clntSock? servSock:clntSock);
FD_SET(clntSock, &read_set );
fd_readset.insert(clntSock);
}
}
}
static const int maxLog=10000;
int main()
{
int-servSock;
信号(信号管、信号灯);
if((servSock=socket(AF\u INET,SOCK\u STREAM,0))<0)
{
printf(“套接字创建失败\n”);
出口(-1);
}
int-val=1;
if(setsockopt(servSock,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val))=clntSock?servSock:clntSock);
FD_集(clntSock和read_集);
fd_readset.insert(clntSock);
}
}
}
该函数使用起来令人沮丧;每次调用它之前都必须设置它的参数,因为它会修改它们。您所看到的是一个演示,演示了如果不在循环中每次设置fd_集会发生什么。您必须在每次迭代中填充fd_集。最好的方法是在某处维护您的FD集合,并将select调用所需的FD集合放入临时FD_集合中
如果需要处理大量客户端,可能必须更改FD_SETSIZE(在/usr/include/sys/select.h
中)宏
快乐网络编程:)您已经有了正确的答案-在每次调用
选择(2)
之前重新初始化fd\u集
我想为您指出一个更好的选择——Linux提供了一个功能。虽然它不是标准的,但它更方便,因为您只需要设置等待一次的事件。内核为您管理文件描述符事件表,因此效率更高epoll
还提供边缘触发功能,其中仅对描述符上的状态更改发出信号
为了完整性,BSD提供了Solaris
还有一件事:您的代码在客户端和服务器之间有一个众所周知的竞争条件。看看。如果在每次调用select之前不重置timeval结构,同样的效果似乎也会发生。我在类似的代码中遇到了同样的问题。在每次调用select()之前,我都会按照建议进行初始化,这样做很有效。在这种情况下的代码中,只要将两行引入循环就可以工作
FD_ZERO(&read_set);
FD_SET(servSock, &read_set);
谢谢你的帮助。我按照您的建议在循环开始时重置了fs_设置,现在可以正常工作了。谢谢!我在这件事上大发雷霆。poll
在POSIX中是标准化的。但是它没有比select
更好。一般建议:使用poll()而不是select()。您必须在select
中使用&tv
而不是tv
,POSIX说select()
函数可以修改超时参数。据推测,如果您所在的系统确实对其进行了修改,则其修改后的值会记录到超时过期之前的剩余时间,如果超时确实过期,则该时间为零,因此在第一次迭代后,调用会退化为轮询,因为归零的超时表示“立即返回”,而不是“必要时等待”。