2014-10-30 50 views
0

說明'的ServerSocket.accept()' 循環,不SocketTimeoutException(Java)的(替代解決方案)

我重新審視我曾經教過自己的Java項目。

在這個項目中,我希望能夠阻止服務器接受新客戶端,然後在退出JVM之前執行一些「清理」操作。

在該項目中我用下面的風格爲客戶接受/手柄循環:

//Exit loop by changing running to false and waiting up to 2 seconds 
ServerSocket serverSocket = new ServerSocket(123); 
serverSocket.setSoTimeout(2000); 

Socket client;  
while (running){ // 'running' is a private static boolean 
    try{ 
     client = serverSocket.accept(); 
     createComms(client); //Handles Connection in New Thread 
    } catch (IOException ex){ 
     //Do Nothing 
    } 
} 

在這種方法中SocketTimeoutException將每2秒拋出,如果有連接任何客戶端,和我不除非有必要,否則就像依靠正常操作的例外。

我一直在用下面的風格實驗爲了儘量依靠例外正常運行:

//Exit loop by calling serverSocket.close() 
ServerSocket serverSocket = new ServerSocket(123); 

Socket client;  
try{ 
    while ((client = serverSocket.accept()) != null){ 
     createComms(client); //Handles Connection in New Thread 
    } 
} catch (IOException ex){ 
    //Do Nothing 
} 

在這種情況下,我的意圖是,一個異常將只當我打電話serverSocket.close拋出()或者是出了什麼問題。

問題

是否有這兩種方法的任何顯著的差異,或者是它們都可行的解決方案?

我完全自學成功,所以我不知道我是否無緣無故地重新發明了車輪,或者我已經想出了一些好東西。

我一直在潛伏着一段時間,這是我第一次無法找到我需要的東西。

請隨時提出完全不同的方法= 3

+0

「我不喜歡依賴正常操作的例外,除非有必要」OMG另一個。這是必要的。 'setSoTimeout()'機制就是爲了這個目的而提供的,'SocketTimeoutException'是它的接口的一部分。不要讓任意編程美學妨礙實現正確的代碼。以什麼方式強制拋出'IOException:socket closed'比捕獲'SocketTimeoutException'更好? – EJP 2014-10-30 22:43:00

+0

我不確定在這種情況下是否有必要,這就是我問的原因。我最初的想法是拋出一個異常會更好,可能每2秒拋一次。 – 2014-10-31 08:03:32

回答

1

第二種方法的問題是,如果在while循環中發生異常,服務器將會死亡。

第一種方法更好,但您可能想使用Log4j添加日誌記錄異常。

while (running){ 
    try{ 
     client = serverSocket.accept(); 
     createComms(client); 
    } catch (IOException ex){ 
     // Log errors 
     LOG.warn(ex,ex); 
    } 
} 
+0

乾杯,你的回答指出我要避免使用SOTimeout,只需關閉套接字就可以強制執行一個非常乾淨,簡單的方法:) – 2014-11-07 15:55:16

+0

是的,這是一個好主意。編寫服務器很有趣:-) – 2014-11-07 23:44:23

0

非阻塞IO是你在找什麼。除非返回SocketChannelSocket的非阻塞替代),否則它將返回null(如果當前沒有要接受的連接)。

這將允許您刪除超時,因爲沒有任何東西會被阻塞。

您還可以註冊一個Selector,它會告知您何時有連接可以接受或何時有數據要讀取。我有這並不使用一種選擇器,here的一個小例子,以及非阻塞的ServerSocket

編輯:萬一出問題時我的鏈接,這裏是非阻塞IO的例子中,沒有一個選擇,接受連接:

class Server { 
    public static void main(String[] args) throws Exception { 
      ServerSocketChannel ssc = ServerSocketChannel.open(); 
      ssc.configureBlocking(false); 

      while(true) { 
       SocketChannel sc = ssc.accept(); 

       if(sc != null) { 
        //handle channel 
       } 
      } 
    } 
} 
+0

感謝您的建議! 用新玩具修補的時間= 3 – 2014-10-31 08:13:32

-1

第二種方法是更好的(你提到的理由:依託於正常的程序流程的異常是不是一個好的做法)allthough你的代碼表明,serverSocket.accept()可以返回null,它不能。該方法可以拋出各種異常(請參閱api-docs)。您可能想要捕捉這些例外情況:服務器不應該在沒有很好理由的情況下停機。

我一直使用具有良好的成功第二種方法,但增加了一些代碼,使其更加穩定/可靠:看到我拿上它here(單元測試here)。要考慮的其中一個「清理」任務是給處理客戶端通信的線程留出一些時間,以便這些線程可以完成或正確通知客戶端連接將被關閉。這樣可以防止在連接突然丟失/關閉之前客戶端不確定服務器是否完成重要任務的情況。

+0

第二種方法與他提到的原因相同。它只是爲'SocketTimeoutException'交換'IOException'。 – EJP 2014-10-30 22:44:32