Multi Thread TCP Socket Programming

In the previous tutorial we have learned how to implement a very basic TCP communication between a client and a server.
But as you mentioned the server is capable to handle only one client at the time.

So, we show you how to write a more advanced multi-threaded Server to handle several clients simultaneously.

Doing some tasks simultaneously (handling several clients) means that we should design our server in a multi-threaded fashion.

Handling a clients means:
  • sending message to the client
  • receiving clients messages
And we should do this for more than one client at the time plus we still should listen to the port for potential new clients!

Listening to the port will happen in the main Server program thread but for handling individual clients we write the CliendHandler class which implements runnable interface.

In java for creating a thread we have 2 ways:
  1. Extending Thread class (our class inherits from Thread class)
  2. Implementing Runnable interface

We choose the second way in this example since it is a cleaner approach (my opinion).

ClientHandler class
package com.blogspot.codetoearn.advancedtcpsocket.server;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * http://codetoearn.blogspot.com/
 *
 * @author ehsun7b
 */
public class ClientHandler implements Runnable {

  private Socket clientSocket;

  public ClientHandler(Socket clientSocket) {
    this.clientSocket = clientSocket;
  }    

  @Override
  public void run() {
    try {
      /* getting input and output streams of the client socket */
      OutputStream outputStream = clientSocket.getOutputStream();
      InputStream inputStream = clientSocket.getInputStream();

      /* sending welcome message to the client */
      String message = "Welcome! You are connected.\n";
      outputStream.write(message.getBytes());
      outputStream.flush();

      /* getting the client reply */
      int character = inputStream.read();

      while (character != -1) {
        System.out.print((char) character);
        character = inputStream.read();
      }

      inputStream.close();
      outputStream.close();
    } catch (Exception ex) {
      System.out.println("Error: " + ex.getMessage());
    }
  }
}

So in the server class, the ServerSocket object accepts any incoming connection and create on ClientHandler object and give it the new socket.

Server class
package com.blogspot.codetoearn.advancedtcpsocket.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * http://codetoearn.blogspot.com/ 
 * @author ehsun7b
 */
public class Server {

  public static final int port = 12345;
  private ServerSocket serverSocket;

  public void listen() {
    try {
      /* creating the serverSocket object */
      serverSocket = new ServerSocket(port);
      
      while (true) {
        Socket socket = serverSocket.accept();
        /* creating a client handler and give the socket to it*/
        ClientHandler clientHandler = new ClientHandler(socket);
        Thread thread = new Thread(clientHandler);
        thread.start();
      }
    } catch (IOException ex) {
      System.out.println("Error: " + ex.getMessage());
    }
  }
  
  public static void main(String[] args) {
    new Server().listen();
  }
}

And finally our client which a simple TCP socket client like the one we have seen in the last example. But we use some simple mechanism to generate 100 random messages to the server from each Client object, to have a simple simulation.

Client class:

package com.blogspot.codetoearn.advancedtcpsocket.client;

import com.blogspot.codetoearn.advancedtcpsocket.utils.Utils;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * http://codetoearn.blogspot.com/
 * @author ehsun7b
 */
public class Client {
  
  private int port;
  private String host;
  private String name;
  private Socket socket;

  public Client(int port, String host, String name) {
    this.port = port;
    this.host = host;
    this.name = name;
  }
  
  public void Connect() {
    try {
      /* creating the socket and trying to connect */
      socket = new Socket(host, port);

      /* getting input and output streams of the socket */
      OutputStream outputStream = socket.getOutputStream();
      InputStream inputStream = socket.getInputStream();

      /* getting the server message */
      int character = inputStream.read();

      while (character != -1 && character != '\n') {
        System.out.print((char) character);
        character = inputStream.read();        
      }
      
      /* sending 100 random messages to the server */
      String[] messages = Utils.randomMessages(100);
      
      for (int i = 0; i < messages.length; i++) {
        String msg = name + ": " + messages[i];        
        outputStream.write(msg.getBytes());
        outputStream.flush();
        Thread.sleep(1000); // wait for 1 second
      }

      inputStream.close();
      outputStream.close();
    } catch (Exception ex) {
      System.out.println("Error: " + ex.getMessage());
    }
  }
  
  /* client program */ 
  public static void main(String[] args) {
    new Thread(new Runnable() {

      @Override
      public void run() {
        new Client(12345, "localhost", "client1").Connect();
      }
    }).start();
    
    new Thread(new Runnable() {

      @Override
      public void run() {
        new Client(12345, "localhost", "client2").Connect();
      }
    }).start();
  }
}

Download the complete code here!

No comments:

Post a Comment