2013-03-21 23 views
18

Mam problem z używaniem ServerSocket w mojej aplikacji.Tworzenie ServerSocket w osobnym wątku?

Tworzę ServerSocket w konstruktorze mojej aplikacji. Konstruktor gniazda wywołuje metodę accept(), aby oczekiwać na połączenie klienta.

Problem polega na tym, że metoda accept() blokuje całą moją aplikację, dopóki klient się nie połączy. Chciałbym zapytać, czy istnieje alternatywa dla utworzenia całego ServerSocket w osobnym wątku, że konstruktor metody ServerSocket i accept() jest wywoływany obok mojej głównej aplikacji?

Edit:

Dzięki Olivier za radę, strzelaj .accept do runnable i tworząc puli wątków do obsługi clientconnections.

Ów mój kod teraz:

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."); 
       } 

      } 
     }; 

Everythings działa prawidłowo! Dzięki!

+0

próbował przeniesienie kodu związanego z gniazdem w osobnym wątku? każdy konkretny problem napotykany? – Ankit

+0

Spójrz na java.nio.channels.AsynchronousServerSocketChannel i sprawdź, czy spełnia on twoje wymagania. – Crollster

+0

Albo jeszcze lepiej, spójrz na to pytanie: http://stackoverflow.com/questions/8940747/how-should-i-use-asynchronousserversocketchannel-for-accepting-connections – Crollster

Odpowiedz

34

Zazwyczaj używam do tego wątków N + 1: jeden dla serwera ServerSocket, aby uniknąć blokowania całej aplikacji oczekującej na połączenie klienta; i N wątków do przetwarzania żądań klienta, gdzie N jest wielkością puli wątków (zalecam użycie puli wątków w celu utworzenia nowego wątku na klienta).

Oto przykład (tylko kodowane go, może chcesz mieć lepsze zarządzanie wyjątku i takie, ale to jest minimalny przykład roboczych)

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

Z obsługą wątków obsługujących klientów, w jaki sposób obsługiwać Odbieranie i wysyłanie danych do i od klienta? Jednym z rozwiązań, które widziałem kilka tygodni temu było to, że Hanlder ma również 2 wątki, jeden do wysyłania i drugi do odbierania danych. – Loki

+0

Ponadto, aby uzyskać bardzo podobne, ale nieco bardziej opisowe podejście do tego tematu, zobacz następujący artykuł: [http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html](http: //tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html) –

+0

Ten kod nie pomaga przeciwko atakowi typu "odmowa usługi", gdzie [zaakceptuj] (http://man7.org/linux/ man-pages/man2/accept.2.html) jest blokowany (lub dławiony) przez atakującego. Taki napastnik uniemożliwi serwerowi przyjmowanie nowych klientów. –