2013-03-21 140 views
18

我在我的應用程序中使用ServerSocket時遇到問題。在單獨的線程中創建ServerSocket?

我在我的應用程序的構造函數中創建了ServerSocket。套接字的構造函數調用accept()方法來等待客戶端連接。

問題是,accept()方法凍結我的整個應用程序,直到客戶端連接。所以我想問一下,是否有另一種方法可以在單獨的線程中創建整個ServerSocketServerSocket及其accept()方法的構造函數在我的主應用程序旁邊調用?

編輯:

感謝奧利弗的意見,把。接受成可運行和創建線程池來處理clientconnections。

,現在這就是我的代碼:

public void start(){ 

     final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10); 

     Runnable serverTask = new Runnable() { 
      @Override 
      public void run() { 

       try { 
        serverSocket = new ServerSocket(port); 

        while (true) { 
         Socket clientSocket = serverSocket.accept(); 
         objectout = new ObjectOutputStream(clientSocket.getOutputStream()); 
         clientProcessingPool.submit(new ClientTask(clientSocket,objectout)); 
        } 
       } catch (IOException e) { 
        System.err.println("Accept failed."); 
       } 

      } 
     }; 

萬物運行良好!謝謝!

+0

試圖在單獨的線程移動插座相關的代碼?任何具體的問題面臨? – Ankit 2013-03-21 07:43:41

+0

查看java.nio.channels.AsynchronousServerSocketChannel並查看它是否符合您的要求。 – Crollster 2013-03-21 07:47:31

+0

還是更好,請看看這個問題:http://stackoverflow.com/questions/8940747/how-should-i-use-asynchronousserversocketchannel-for-accepting-connections – Crollster 2013-03-21 07:49:17

回答

34

通常情況下,我使用N + 1個線程:ServerSocket,避免阻塞整個應用程序等待客戶端連接;和N個線程來處理客戶端的請求,N是線程池的大小(我建議使用線程池來爲每個客戶端創建一個新線程)。

下面是一個例子(只是編碼,你可能希望有更好的異常管理等,但這個是最小的工作示例)

public class Server { 

    public static void main(String[] args) { 
     new Server().startServer(); 
    } 

    public void startServer() { 
     final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10); 

     Runnable serverTask = new Runnable() { 
      @Override 
      public void run() { 
       try { 
        ServerSocket serverSocket = new ServerSocket(8000); 
        System.out.println("Waiting for clients to connect..."); 
        while (true) { 
         Socket clientSocket = serverSocket.accept(); 
         clientProcessingPool.submit(new ClientTask(clientSocket)); 
        } 
       } catch (IOException e) { 
        System.err.println("Unable to process client request"); 
        e.printStackTrace(); 
       } 
      } 
     }; 
     Thread serverThread = new Thread(serverTask); 
     serverThread.start(); 

    } 

    private class ClientTask implements Runnable { 
     private final Socket clientSocket; 

     private ClientTask(Socket clientSocket) { 
      this.clientSocket = clientSocket; 
     } 

     @Override 
     public void run() { 
      System.out.println("Got a client !"); 

      // Do whatever required to process the client's request 

      try { 
       clientSocket.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

} 
+0

使用線程池處理客戶端,您如何處理接收和發送數據到客戶端和從客戶端發送數據?我幾周前看到的一個解決方案是Hanlder也有2個線程,一個用於發送,另一個用於接收數據。 – Loki 2013-03-21 07:40:04

+0

此外,對於這個主題非常類似但稍微更具描述性的內容,請參閱以下文章:[http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html](http: //tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html) – 2015-05-12 12:37:40

+0

這段代碼並不能幫助抵禦拒絕服務攻擊,其中[accept](http://man7.org/linux/ man-pages/man2/accept.2.html)被攻擊者阻止(或限制)。這樣的攻擊者會阻止你的服務器接受新的客戶端。 – 2016-11-17 15:14:40