2014-04-30 83 views
1

我有一個程序,它可以作爲一個簡單的tcp服務器,它將接受和服務多達4個客戶端。我寫了下面的代碼片段來存檔這個目標,更清楚的是,我用一些「魔術數字」替換了一些MACRO。如何在套接字編程中正確拒絕客戶端的連接?

while(1) { 
    int ret = 0; 
    /// 
    // sock_ is the listening socket, rset_conn_ only contains sock_ 
    // 
    if(select(sock_ + 1, &rset_conn_, NULL, NULL, &timeo_) <= 0) { 
    ret = 0; 
    } 

    if(FD_ISSET(sock_, &rset_conn_)) { 
    ret = 1; 
    } 

    /// 
    // because the rule select() clears file descriptor and updates timeout is 
    // complex, for simplicity, let's reset the sock_ and timeout 
    // 
    FD_SET(sock_, &rset_conn_); 
    timeo_.tv_sec = 0; 
    timeo_.tv_usec = 500000; 

    if(! ret) { 
    continue ; 
    } 

    /// 
    // csocks_ is an 4 integer array, used for storing clients' socket 
    // 
    for(int i = 0 ; i < 4 ; ++i) { 
    if((-1 == csocks_[i]) && (-1 != (csocks_[i] = accept(sock_, NULL, NULL)))) { 
     break ; 
    } 
    } 
} 

現在,當小於4個客戶端連接,這個代碼片斷工作正常,但在第5客戶端連接,你可以看到,它不會在循環接受,這會導致此類一個問題:在下面的循環中,而,select()調用總是返回sock_ bit rset_conn_ set ---只是因爲我不接受它!!

我知道我不應該只是忽略它(不接受)在循環,但我怎麼能告訴內核處理得當「我不想接受這個客戶,所以沒有告訴我這客戶想再連接我!「?

任何幫助將不勝感激..

更新:

我不能停止調用select()調用,因爲客戶端已連接可能會斷開,然後我的程序將有空間容納新客戶端。我需要保持監聽套接字來接受連接,而不是在達到一點時停止監聽。

+0

「我需要繼續監聽套接字來接受連接」:不,你不知道。您可以輕鬆地在*客戶端*套接字(我認爲您正在執行*無論*)上觸發一次,並在檢測到丟棄時恢復偵聽循環。在我看來,你正試圖手動推出自己的'listen()'。這是一個我不建議重新創建的輪子。 – WhozCraig

回答

5

爲什麼你問一個你不想要的答案?如果您不想被告知有未被接受的連接,請停止在偵聽套接字上調用select

我無法停止調用select()調用,因爲已連接的客戶端可能會斷開連接,然後我的程序將爲新客戶端提供空間。我需要繼續監聽套接字以接受連接,而不是在達到一個點時停止監聽。

您可以停止呼叫選擇現在。當客戶端斷開連接時,再次開始撥打select。只詢問你想要的答案。

+0

我已經更新了我無法停止調用'select()'的原因 –

+1

查看我的更新。這是沒有意義的。 –

+0

啊......你說的方法有點是編碼技巧,實際上,我想知道是否有辦法告訴內核忽略這個客戶端*這次*?或者,如果我可以通過發送RST數據包來處理這種連接,那麼我已經處理了這個「select」連接不會再打擾我的連接了嗎? –

3

沒有套接字API告訴內核忽略掛起的連接(在Windows上,在WSAAccept()中有一個回調,但這是一個特定於Microsoft的擴展)。

在大多數平臺上,您必須要麼:

  1. close()當你的陣列填補了監聽套接字,那麼當客戶端斷開連接重新打開。

  2. accept()客戶端,但立即close()它如果數組已滿。

  3. 停止呼叫select()accept()而您的數組已滿。任何處於積壓狀態的客戶端最終都會超時,除非您的數組已滿並且您的客戶端在超時之前處於待定狀態。

+0

實際上在非阻塞模式下。只是不要選擇監聽套接字。 – EJP

+1

避免'select()'不會阻止操作系統將掛起的客戶端放入監聽套接字的積壓隊列中,直到應用程序調用accept()或客戶端超時並斷開連接。 –

+0

對我來說,避免在收聽套接字上選擇是可以的。 'accept()'和立即'close()'似乎有點多餘且麻煩。我認爲操作系統應該爲我們提供一個我們可以拒絕客戶端連接的接口,比如發回RST消息。 –

2

當存在四個現有客戶端時,您可以從readFD中刪除偵聽套接字,並在掉落時將其放回,但我沒有看到該點。爲什麼只有四個客戶?爲什麼不取消限制並消除整個問題?真正的服務器不是這樣構建的。

+0

非常感謝!我知道了。這是一個設計問題,實際上這個數字是32,爲了簡單起見,我把它減少到了4。 –

+0

而且,這個程序在嵌入式設備上運行,我不希望這個程序耗盡系統資源。 –

+0

請注意,當您沒有選擇偵聽套接字時,這不會拒絕連接。他們只會排隊,但對我來說這似乎更可取。當積壓隊列填滿時,您將開始獲取連接拒絕或超時,具體取決於平臺的行爲。 – EJP