2008-11-12 53 views
6
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套接字接收到数据,它也会超时。在我看来,浪费资源必须每次都清空和填充设置。

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

+0

我认为你理解的一些代码对于理解为什么表现得那么重要。 – SoapBox 2008-11-12 23:27:22

回答

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类操作系统有几个:

  • 为Linux,epoll的()
  • 为FreeBSD/NetBSD的/ OpenBSD的/ MacOS X系统,kqueue的( )
  • 用于Solaris为/ dev/poll的

的API是不同的,但它们本质上都是有状态的内核接口维持一组活动文件描述。一旦将fd添加到该集合中,您将被通知该fd上的事件,而不必再次将其传入。

7

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

在使用它之前,请始终初始化fd_set。

+0

我知道FD_ISSET,但我还没有包括它,因为截至目前我只列出一个套接字(稍后我会添加更多的套接字)。 那么现在有办法可以“重用”而不必先设置fd_set? – deadcyclo 2008-11-12 23:53:31

+0

select()的记录行为包括适当地修改集合。要引用实用程序员,“'选择'不会被打破”。 – bk1e 2008-11-13 03:44:00

0

这就是选择作品的方式。如果你有多个套接字,它效果最好,而且更有意义。这点很重要:你正在选择跨越多个套接字。如果你想从一个套接字读取,只需读取或接收它。

+1

阅读不提供超时。因此使用select。 +事实上,我将在开发阶段稍后添加第二个套接字。 – deadcyclo 2008-11-12 23:54:49