2011-01-25 126 views
4

我正在做一個C++項目,需要一個服務器創建一個新的線程來處理連接,每次accept()返回一個新的套接字描述符。我使用select來決定連接嘗試何時發生以及客戶端通過新創建的客戶端套接字(接受創建的客戶端套接字)發送數據的時間。因此,有兩個函數和兩個選擇 - 一個用於輪詢專用於偵聽連接的套接字,一個用於輪詢在新連接成功時創建的套接字。select()總是返回1; TCP連接套接字問題在C++

第一種情況的行爲是我所期望的 - FD_ISSET僅在請求連接時才爲偵聽套接字的ID返回true,並且在下次連接嘗試之前爲false。第二種情況不起作用,即使代碼與不同的fd_set和套接字對象完全相同。我想知道這是否源於TCP套接字?由於它們的流暢性質,這些套接字在被選擇器輪詢時是否總是返回true?

//working snippet 

struct timeval tv; 
tv.tv_sec = 0; 
tv.tv_usec = 500000; 
fd_set readfds; 
FD_ZERO(&readfds); 
FD_SET(sid,&readfds); 

//start server loop 
for(;;){ 

    //check if listening socket has any client requrests, timeout at 500 ms 
    int numsockets = select(sid+1,&readfds,NULL,NULL,&tv); 
    if(numsockets == -1){ 
     if(errno == 4){ 
      printf("SIGINT recieved in select\n"); 
      FD_ZERO(&readfds); 
      myhandler(SIGINT); 
     }else{ 
      perror("server select"); 
      exit(1); 
     } 
    } 

    //check if listening socket is ready to be read after select returns 
    if(FD_ISSET(sid, &readfds)){ 
     int newsocketfd = accept(sid, (struct sockaddr*)&client_addr, &addrsize); 
     if(newsocketfd == -1){ 
      if(errno == 4){ 
       printf("SIGINT recieved in accept\n"); 
       myhandler(SIGINT); 
      }else{ 
       perror("server accept"); 
       exit(1); 
      } 
     }else{ 
      s->forkThreadForClient(newsocketfd); 
     } 
    } 






//non working snippet 

//setup clients socket with select functionality 
struct timeval ctv; 
ctv.tv_sec = 0; 
ctv.tv_usec = 500000; 
fd_set creadfds; 
FD_ZERO(&creadfds); 
FD_SET(csid,&creadfds); 



for(;;){ 

    //check if listening socket has any client requrests, timeout at 500 ms 
    int numsockets = select(csid+1,&creadfds,NULL,NULL,&ctv); 
    if(numsockets == -1){ 
     if(errno == 4){ 
      printf("SIGINT recieved in client select\n"); 
      FD_ZERO(&creadfds); 
      myhandler(SIGINT); 
     }else{ 
      perror("server select"); 
      exit(1); 
     } 
    }else{ 
     printf("Select returned %i\n",numsockets); 
    } 

    if(FD_ISSET(csid,&creadfds)){ 


     //read header 
     unsigned char header[11]; 
     for(int i=0;i<11;i++){ 
      if(recv(csid, rubyte, 1, 0) != 0){ 
       printf("Received %X from client\n",*rubyte); 
       header[i] = *rubyte; 
      } 
     } 

任何幫助,將不勝感激。


感謝您的回覆,但我不認爲它有很多待處理的循環內的超時值。我對它進行了測試,即使電視被重置並且fd_set在每次服務器循環時被清零,select仍然立即返回1。我覺得select對待我的TCP套接字有問題。任何時候我設置選擇最高的套接字ID來包含我的TCP套接字,它會立即返回該套接字集。另外,客戶端不發送任何東西,只是連接。

+0

您能否修復您的縮進以便它看起來正確?所有的代碼都像這樣左邊的邊緣被衝上去很難。 – 2011-01-25 07:41:46

+0

你說這是行不通的。但它是做什麼呢? – BatchyX 2011-01-25 08:38:16

回答

6

有一件事你必須是你叫select()之前的tv值每次重置爲所需的超時。 select()函數更改tv中的值以指示在從函數返回後,超時中剩餘多少時間。如果你沒有這樣做,你的select()調用將最終使用零的超時,這是不高效的。

其他一些操作系統以不同的方式實現select(),使得它們不會更改tv的值。 Linux確實改變了它,所以你必須重置它。

3

移動

FD_ZERO(&creadfds); 
FD_SET(csid,&creadfds); 

進入循環。函數select()報告此結構中的結果。您已經檢索到結果

FD_ISSET(csid,&creadfds);