2009-10-02 31 views
6

Tôi có một thread máy chủ với mã này:Cách bỏ chặn một chuỗi bị chặn trên 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); 
    } 
} 

và một phương pháp tắt máy như thế này:

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

Tôi muốn tắt máy mà có thể mở khóa chủ đề đó đang chờ đợi trên server.accept() nếu không tôi phải đợi kết nối trước khi tắt máy chủ.

Tôi không thể làm server.close() trong tắt máy() vì tôi phải báo hiệu cho khách hàng đã đăng ký rằng máy chủ đang ngừng hoạt động.

Bất kỳ ý tưởng nào?

Trả lời

4

Tôi cố gắng thiết kế mã của mình để mã có thể "tắt" với gián đoạn. Chủ yếu, điều này là do khung công tác Executor trong gói đồng thời của Java sử dụng interrupt để hủy các tác vụ đang chạy. Ngoài ra, nhiệm vụ "tắt máy" không phải biết bất kỳ nội bộ nào của nhiệm vụ bị giết.

Tuy nhiên, một cuộc gọi đến accept sẽ không đáp ứng với một ngắt trừ nó là created from a ServerSocketChannel. Một máy chủ tạo ra với một constructor ServerSocket sẽ bỏ qua ngắt, và tôi đã không tìm thấy một cách để cấu hình lại này.

Nếu bạn không thể thay đổi mã tạo máy chủ, hãy sắp xếp một chuỗi khác để gọi close trên ổ cắm máy chủ. Điều này cũng sẽ làm tăng ngoại lệ trong chuỗi bị chặn trên accept, bất kể phương thức được sử dụng để tạo ổ cắm máy chủ.

Điều này hóa ra lại là một nỗi đau thực sự lớn khi sử dụng SSL. Một ổ cắm JSSE không được tạo ra từ InterruptibleChannel và sẽ không phản hồi một ngắt đơn giản trên luồng.


Tôi vừa nhận thấy rằng câu hỏi cho biết máy chủ không thể đóng mà không thông báo cho khách hàng. Việc ngắt kết nối thành công một ổ cắm sẽ dẫn đến kết quả của nó.

Khi gọi đến accept, đây không phải là vấn đề vì máy khách không được kết nối nếu ổ cắm máy chủ bị chặn trong chấp nhận. Đó chỉ là vấn đề đối với Socket trường hợp, đại diện cho các kết nối hiện tại.

Nếu điều đó không đáp ứng các yêu cầu thông báo, bạn có thể cần phải làm lại để sử dụng chế độ không chặn của NIO ServerSocketChannel.

+0

mmm câu trả lời hay .. Có lẽ tôi thay đổi cách tiếp cận vấn đề. Tôi quản lý tắt máy chủ ở phía máy khách với try-catch. –

0

Bạn đã thử Thread.interrupt() chưa?

Nếu thread này bị chặn trong một I/O hoạt động trên một kênh ngắt sau đó kênh này sẽ được khép kín, tình trạng ngắt của chủ đề sẽ được thiết lập, và các chủ đề sẽ nhận một ClosedByInterruptException.

Nếu thread này bị chặn trong một Selector sau đó tình trạng ngắt của chủ đề sẽ được thiết lập và nó sẽ trở lại ngay lập tức từ các hoạt động lựa chọn , có thể với một số không phi giá trị, cũng giống như khi của selector wakeup phương thức đã được gọi.

+0

Tôi đã thử với this.interrupt(); trong shutdown() nhưng không hoạt động ... –

+0

Bạn cần phải gọi nó trên chuỗi bạn muốn ngắt (ví dụ như bị chặn) –

2

Bạn sẽ có thể đóng socket từ một sợi khác.

2

Không gián đoạn (phụ thuộc vào điểm ngắt theo cùng cách hủy phụ thuộc vào điểm hủy) cũng như không đóng được (chấp nhận không trả lời để đóng bộ mô tả tệp của nó). Bạn sẽ phải giao tiếp với sự chấp nhận (thử sendto, với một thông báo tắt máy) để thông báo cho nó không tiếp tục chấp nhận. Ít nhất đây là trường hợp trên linux; không biết nó như thế nào trên các nền tảng khác.

+0

làm thế nào để bạn giải quyết vấn đề này cuối cùng? nhiều người nói gần sẽ làm việc, nhưng nó không hoạt động trong trường hợp của tôi chạy trên Linux. – Djvu

1

Tôi đã phải đối mặt với cùng một vấn đề. Các giải pháp làm việc của tôi bao gồm đóng đối tượng ServerSocket (serverSocket.close()); làm điều này sẽ gây ra phương thức accept() để ném một SocketException, đó là những gì bạn muốn làm.

Vincent

Các vấn đề liên quan