2011-04-11 79 views
5

我對TCP客戶端 - 服務器通信的結構如下:Java:停止線程化TCP服務器的好方法?

  • 在服務器啓動時服務器啓動 受體螺紋,接受客戶 連接並傳遞的ServerSocket 給它。
  • 當客戶端連接到達, 受體線程調用accept()上 的ServerSocket並提交客戶 的處理作業工作線程 (由執行/線程池),並提供客戶端套接字給它。
  • 工人循環從 客戶端套接字流中讀取數據,對其進行處理併發送回復。

問題是如何優雅地停止整個系統?我可以通過關閉ServerSocket來停止acceptor線程。它將導致accept()阻塞調用來拋出SocketException。但如何阻止工人?他們從流中讀取並且此通話被阻止。根據this流不會拋出InterruptedException,因此worker不能被中斷()編輯。

它看起來像我需要從另一個線程關閉工人套接字,對嗎?爲此,應將套接字設置爲公共字段,或者應在工作人員中提供關閉套接字的方法。這會很好嗎?或者可能是我的整個設計有缺陷?

回答

3

您的模型正常工作。中斷IO等非可中斷結構的最好方法是關閉套接字。你當然可以在進入阻塞狀態之前處理它,但是如果IO功能不會對中斷做出反應,你真的沒有很多好的選擇

2

我會建議使用布爾標誌,工人定期檢查。調用標誌shouldStop,如果它設置爲true,則工人清理並死亡。遵循這種方法將允許您執行一些清理代碼,以便不會使資源懸掛等。

+0

當I/O中的工作者被阻塞時,我無法檢查這個標誌 – 2011-04-11 17:24:39

+0

最佳做法是使用Thread.interrupted()。這是標準的解決方案,可以在ThreadPool中正常工作。 – 2011-04-11 19:04:45

+0

@Andrey Vityuk Thread.interrupted實際上不是很好的做法,因爲它重置了中斷標誌。你可能意味着Thread.interrupt或Thread.isInterrupted。這就是說,正如我在我的回答中所說的,許多IO構造不考慮線程中斷,因此(儘管我部分同意你的評論)它不適用於這種情況。 – 2011-04-12 00:30:53

2

您不能簡單地停止服務器。清理過程可能需要一段時間,因爲您需要確保一致性。

想象一下數據庫服務器,如果您在執行事務時將其關閉,則可能會使其數據不一致。這就是爲什麼它通常需要一段時間才能關閉服務器。

  • 您必須先停止接受服務器中的新連接 。
  • 然後您可以等待 當前工作線程完成 他們的工作,然後關閉 服務器並正式關閉。
  • 或者你強制工作線程 關閉與
    客戶他們的連接(可能使用某種標誌的
    的建議)。這可能是 意味着一些清理,以保持數據 一致,例如恢復 傳輸或您在文件或內存中完成的任何類型的更改 。

根據我的理解,關閉與服務器端客戶端的連接應該會導致客戶端獲得EOF。

[編輯-1]

我已經深入研究在這個問題上有點,只是因爲我沒有在使用了一段時間插座,因爲我發現這個問題有意思。我認爲,由於它已被其他人指出,唯一的選擇是關閉插座,根據Javadocs將自動關閉輸入和輸出流/

如果有線程未被IO阻塞的機會,但處於等待狀態或休眠狀態,我認爲仍然建議爲給定套接字的相應工作線程發出Thread.interrupt();因爲不能確定每個線程的狀態是否被阻塞。

public static class IOServerWorker implements Runnable{ 

     private Socket socket; 

     public IOServerWorker(Socket socket){ 
      this.socket = socket; 
     } 

     @Override 
     public void run() { 
      String line = null; 
      try{ 
       BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
       while((line = reader.readLine())!=null){ 
        System.out.println(line); 
       } 
       reader.close(); 
      }catch(IOException e){ 
       //TODO: do cleanup here 
       //TODO: log | wrap | rethrow exception 
      } 
     } 
    } 
+0

我對此非常瞭解。 「那麼你可以等待當前的工作線程完成他們的工作」 - 如果你再次讀到我的問題,你會發現這是一個問題。工作人員可以通過從套接字流中讀取來阻止。問題是如何優雅地打斷他們。標誌在這裏不起作用,因爲工作人員在處於被阻止的I/O狀態時無法檢查它 – 2011-04-11 15:42:56

+0

「你不能簡單地停止服務器。」實際上,如果你的服務器設計正確(ACID事務和所有) 。導致數據庫提交的更改被認爲發生了,並且不會發生的更改不會發生。使這項工作順利進行是將數據庫與中間綁定的業務邏輯和Web前端分離的一個很好的理由。 – 2011-04-11 17:30:13