2009-10-02 161 views
6

我有一個服務器線程使用此代碼:如何取消阻塞ServerSocket.accept()上阻塞的線程?

public void run() { 
    try { 
     ServerSocket server; 
     EneaLog.printLog("Server is running."); 
     server = new ServerSocket(this.portnumber); 

     while (true) { 
      new EneaServerConnection(server.accept(), this.project,stopped).start(); 
      if (stopped) { 
       EneaLog.printLog("Server safe-shutdown completed."); 
       EneaLog.printLog("Hi!"); 
       server.close(); 
       return; 
      } 
     } 
    } catch (IOException ex) { 
     Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex); 
     project.getExceptionHandler().handler(ex); 
    } 
} 

和關斷的方法是這樣的:

public void shutdown() { 
    EneaLog.printLog("Server shutdown NOW!"); 
    stopped = true; 
} 

我想要關機可以解禁等待server.accept線程(),否則我在服務器關閉之前必須等待連接。

我不能在shutdown()中執行server.close(),因爲我必須向已註冊的客戶端發送服務器正在關閉的信號。

任何想法?

回答

4

我嘗試設計我的代碼,以便它可以通過中斷「關閉」。這主要是因爲Java的併發包中的Executor框架使用interrupt來取消正在運行的任務。此外,「關機」任務不必知道被殺任務的內部任何內容。

然而,accept,呼叫不會以中斷響應除非這是created from a ServerSocketChannel.ServerSocket構造函數創建將忽略中斷服務器,我還沒有找到一種方法來重新配置這一點。

如果您無法更改創建服務器的代碼,請安排另一個線程在服務器套接字上調用close。無論用於創建服務器套接字的方法如何,這也會在阻止accept的線程中引發異常。

這在使用SSL時會變得非常痛苦。 JSSE套接字不是從InterruptibleChannel創建的,並且不會響應線程上的簡單中斷。


我剛剛注意到這個問題說服務器不能在沒有通知客戶端的情況下關閉。成功中斷套接字將導致其關閉。

accept的調用中,這應該不成問題,因爲如果服務器套接字在接受中被阻塞,則客戶端未連接。這應該只是Socket實例的問題,它們表示當前的連接。

如果不滿足通知要求,可能需要重新使用非阻塞模式下的NIO的ServerSocketChannel

+0

嗯好的答案..也許我改變了解決問題的方法。我用try-catch管理客戶端的服務器關閉。 – 2009-10-02 16:18:54

0

你試過Thread.interrupt()

如果該線程在可中斷 通道阻塞在一個I/O 操作則該信道將是 關閉時,線程的中斷狀態 將被設置,並且該線程將 接收ClosedByInterruptException。

如果該線程被阻塞在 選擇則該線程的中斷 狀態將被設置,它會立即返回 從選擇 操作,可能與非零 值,就好像選擇的 喚醒方法被調用。

+0

我試過用this.interrupt();在關機()但不起作用... – 2009-10-02 16:09:41

+0

你需要在你想中斷的線程(即被阻止的線程)上調用它 – 2009-10-02 16:10:34

2

您應該能夠從另一個線程關閉套接字。

2

既不中斷(這取決於中斷點以相同的方式取消取決於取消點)也不關閉將它做(接受不響應關閉其文件描述符)。您必須與accept進行通信(嘗試sendto,併發出關閉通知)以通知它不會繼續接受。至少在Linux上是這樣的;不知道在其他平臺上是什麼樣的。

+0

終於如何解決這個問題?很多人都說close會起作用,但是在我的linux上運行的情況下它並不起作用。 – Djvu 2015-01-10 08:38:56

1

我一直面對同樣的問題。我的工作解決方案包括關閉ServerSocket對象(serverSocket.close());這樣做會導致accept()方法拋出一個SocketException,這就是你想要做的。

Vincent