c中有刺激性的select()行为

时间:2008-11-12 23:24:45

标签: c sockets select timeout

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;
    FD_ZERO(&set); 
    FD_SET(sd,&set);

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

工作正常,但是

FD_ZERO(&set); 
FD_SET(sd,&set);

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

没有。它第一次工作,但下次它运行while循环时,即使sd套接字接收数据,它也会超时。在我看来,每次都必须清空和填充设置是浪费资源。

任何人都有一个很好的解释为什么会这样,甚至更好,也许是一个如何避免它的建议?

3 个答案:

答案 0 :(得分:12)

select修改其参数。你真的必须每次重新初始化它。

如果您担心开销,那么在内核中处理完整FD_SET的成本比FD_ZERO的成本更重要。您只想传递最大fd,而不是FD_SETSZIZE,以最小化内核处理。在您的示例中:

switch (select((sd + 1),&set,NULL,NULL,&timeout))

对于具有多个fds的更复杂的情况,通常最终会维护一个最大变量:

FD_SET(sd,&set);
if (sd > max) max = sd;
... repeat many times...

switch (select((max + 1),&set,NULL,NULL,&timeout))


如果你有大量的文件描述符,并且担心将它们包含在内,那么你应该看看select()的一些替代方法。你没有提到你正在使用的操作系统,但对于类Unix操作系统,有一些:

  • for Linux,epoll()
  • for FreeBSD / NetBSD / OpenBSD / MacOS X,kqueue()
  • for Solaris,/ dev / poll

API不同,但它们本质上都是一个有状态的内核接口,用于维护一组活动文件描述。将fd添加到集合后,您将收到有关该fd事件的通知,而无需再次将其连续传递。

答案 1 :(得分:7)

阅读选择手册页。返回的集合只是可以使用的文件描述符。你应该使用FD_ISSET检查每一个是否已设置。

在使用之前始终初始化fd_set。

答案 2 :(得分:0)

这就是选择的方式。如果你有多个套接字,它效果最好,更有意义。这就是重点:你正在选择多个套接字。如果你想从一个插座读取,只需阅读或重新读取它。