2008-11-12 31 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