2013-11-02 57 views
0

我想使用select函數來處理不同的文件描述符。程序啓動時,必須按照間隔開始向其他客戶端發送數據包。我的第一個問題是我如何在主while循環中使用計時器而不中斷while循環和select函數的功能?這是因爲我需要在計時器運行時接受用戶輸入。在選擇函數中檢測超時客戶端

第二個問題是,我不知道,如果我現在需要把發射功能我while循環。當程序進入while循環或者我需要在其他地方使用它時,是否需要編寫send函數?

另外,該程序必須檢測還沒有對一個特定的時間文件描述符。如何檢測哪些文件描述符沒有發送任何數據包到服務器?

下面你可以看到,我至今寫的代碼。你能幫我解決嗎? 我還沒有在這裏使用任何計時器。此外,該程序無法檢測哪個文件描述符已超時。

 FD_ZERO(&masterfds); 
     FD_SET(udp_con, &masterfds); 
     maxfds = udp_con; 

     while(exit == false) 
     { //Do I need to use the send function here? 
      FD_ZERO(&readfds); 
      readfds = masterfds; 

      selectFunc = select(maxfds+1, &readfds, NULL, NULL, &tv); 
      if(selectFunc < 0) 
      { 
       message("error in select"); 
       exit = true; 
      } 
      else if(selectFunc == 0) 
      { //How can I detect which file descriptor is timed out? 
       for(i = 0; i <= maxfds; i++) 
       { 
        if(FD_ISSET(i, &readfds)) 
        { 
         //Doesn't work 
         cout<<"The file descriptor "<<i<<" has timed out"<<endl; 
        } 
       } 
      } 
      else 
      { //The server has received something from a client 

       for(i = 0; i <= maxfds; i++) 
       { 

       } 
      } 
     } 

回答

0

select的最後一個參數是在文件描述符集中等待事件的時間量。您可以使用它來等待事件的預定義時間段,比如說100毫秒。如果該超時在沒有收到任何事件的情況下通過,則select將返回0,並且不會設置任何描述符。

現在,你需要想想一個「積極的」連接從服務器的角度表示。通常情況下,您應該爲該連接上最後收到時的每個fd保留一個單獨的時間戳。發送可以沒有任何問題發生,並且不表示連接仍處於活動狀態。

因此,代碼的結構應當這樣 - 一些粗糙的僞代碼:

select with timeout 
did select return 0: 
    (this means that no data was received for the timeout on any descriptor) 
    (this is the place to check if any descriptor went past its 'active' limit) 
    iterate over all fds: 
    if last_received_timestamp[current_fd] + deadline > current_time: 
     remove fd or do something else 
else: 
    (there is something to read) 
    iterate over descriptors in readfds: 
    read data and process it 
    last_received_timestamp[current_fd] = current_time 

希望這有助於。

其他信息:

如果你想處理這個更統一的方式,試圖尋找到timerfd_create。這可以用來創建看起來像文件描述符的定時器,因此您可以使用select來獲取特定事件的通知。例如,您可以爲每個正常的fd創建一個這樣的timerfd,並在達到截止日期時設置爲過期。這裏的關鍵是每當您收到數據時重新啓動計時器。

一個經典的問題單線程循環像這樣的等待事件,然後處理所有的人依次是:如果服務器變得太忙或者如果連接數據處理需要太多,所有的連接就會看到延遲。更好的架構是使用線程池來處理套接字上的讀/寫操作。這釋放了事件循環,併爲所有客戶端提供了更好的響應時間。但是,這更加複雜,可能超出了您嘗試實現的範圍。

+0

謝謝你,但我不知道,因爲我使用的UDP連接,我不使用accept函數得到一個新的文件描述符爲每一個客戶,我是否需要任何文件描述符添加到我的主人的FD名單? 我現在有點困惑。看來,我將要使用的唯一文件描述符是「udp_con」。那是對的嗎? – Amir

+0

我正在使用linux,只是試圖包含頭文件「sys/timerfd.h」,但它找不到任何具有該名稱的頭文件。我怎樣才能在linux中充分利用timerfd? – Amir