25

I have a problem with using a ServerSocket in my application.

I'm creating the ServerSocket in the constructor of my application. The constructor of the socket calls the accept() method to wait for a client to connect.

The problem is that the accept() method is freezing my whole application until a client connects. So I would like to ask if there's an alternative to creating the whole ServerSocket in a separate thread, that the constructor of the ServerSocket and its accept() method is called beside my main application?

Edit:

Thanks to Olivier for the advice, putting the .accept into a runnable and creating a threadpool to handle the clientconnections.

Thats my code right now:

  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 running fine! Thanks!

Chocolate
  • 414
  • 1
  • 5
  • 16
  • tried moving socket related code in separate thread? any specific problem faced? – Ankit Mar 21 '13 at 07:43
  • Take a look at java.nio.channels.AsynchronousServerSocketChannel and see if it fits your requirement. – Crollster Mar 21 '13 at 07:47
  • Or better still, take a look at this question: http://stackoverflow.com/questions/8940747/how-should-i-use-asynchronousserversocketchannel-for-accepting-connections – Crollster Mar 21 '13 at 07:49
  • my problem is that its not enough to implement the ServerSocket as a thread because the .accept method is already called in its constructor not in its run method. So as soon as i try to create the thread its already freezing my app. – Chocolate Mar 21 '13 at 07:51

1 Answers1

48

Usually, I use N+1 threads for this : one for the ServerSocket, to avoid blocking the whole application waiting for a client to connect; and N threads to process the client's requests, N being the size of the thread pool (I recommend using a thread pool over creating a new thread per client).

Here is an example (just coded it, you may want to have better exception management and such, but this is a minimal working example)

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();
            }
        }
    }

}
Olivier Croisier
  • 5,881
  • 23
  • 32
  • With the threadpool handling the clients, how do you handle Receive and Send Data to and from the client? One solution i saw a few weeks ago was that the Hanlder also has 2 threads, one for sending and one for receiving Data. – Loki Mar 21 '13 at 07:40
  • 1
    Also, for a very similar, yet slightly more descriptive take on this topic, see the following article: [http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html](http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html) – Priidu Neemre May 12 '15 at 12:37
  • This code does not help against the denial of service attack, where [accept](http://man7.org/linux/man-pages/man2/accept.2.html) is blocked (or throttled) by the attacker. Such an attacker would stop your server from accepting new clients. – Alexander Farber Nov 17 '16 at 15:14
  • Sicne it's already 2017, with Java 8 you want to use Lambda rather than anonymous function: `Runnable serverTask = () -> {` /* code here */ } – Christopher Will Aug 21 '17 at 16:05