Multi-threaded Client/Server in Java

What is a Thread?

Developers are accustomed to writing sequential programs where code execution follows a linear path from start to finish. However, in concurrent programming, a thread represents a separate and independent flow of control within a program. Threads allow multiple events or actions to occur simultaneously, addressing the limitations of single-threaded programs. In Java, the java.lang.Thread class plays a vital role in creating and managing threads, enabling developers to utilize the power of parallel execution and synchronization in their applications.

There are two ways to create thread in java;

  1. Implement the Runnable interface (java.lang.Runnable)
  2. By Extending the Thread class (java.lang.Thread)

Multithreading in Java

Multithreading in Java refers to the ability of a program to execute multiple threads concurrently. It allows for parallel execution of different tasks within a program, maximizing resource utilization, especially on systems with multiple CPUs. Multithreading enables simultaneous execution of threads, resulting in improved performance and responsiveness. The concurrent execution of multiple threads is known as multithreading, a powerful feature that enhances the efficiency and scalability of Java programs.

Multithreaded Socket Programming in Java

In the previous example we already saw how a Single Thread Socket Program is running. In that case there is only one client can communicate with the server. It will not allow simultaneous client connections. Try to start another client. You will see that the second client cannot be connected until the first client closes its connection. To allow simultaneous connections we should know multithreaded programming. Here in the following Multithreaded Socket Programming , you can connect more than one client connect to the server and communicate.

How it works?

In a server-client architecture, when a client establishes a connection with the server, the server creates a separate child thread to handle that client's request. This approach allows each client connection to be processed independently and concurrently, without being affected by other incoming requests. By using separate threads for each client connection, the server can efficiently handle multiple clients simultaneously, ensuring responsiveness and scalability.

Socket serverClient=server.accept(); ServerClientThread sct = new ServerClientThread(serverClient,counter);

The ServerClientThread class is a custom class that extends the Thread class in Java. This approach allows for concurrent processing of incoming client requests. Instead of handling the requests within the same thread that accepts the client connection, each connection is assigned to a separate client thread for processing. By doing so, the main thread responsible for listening to incoming requests can stay focused on accepting new connections, minimizing the risk of denying access to clients.

The client threads are responsible for executing the actual request processing. Multiple client threads can be created and run in parallel, allowing the server to handle multiple client requests simultaneously. In the provided example, the client sends a number to the server, and in response, the server calculates the square of the received number and sends it back to the client.

By utilizing individual client threads, the server achieves better scalability and responsiveness, as each client request is processed independently. This multithreaded approach enables efficient utilization of system resources and enables the server to handle concurrent client connections efficiently.

Multithreaded Server Socket program in Java

import java.net.*; import java.io.*; public class MultithreadedSocketServer { public static void main(String[] args) throws Exception { try{ ServerSocket server=new ServerSocket(8888); int counter=0; System.out.println("Server Started ...."); while(true){ counter++; Socket serverClient=server.accept(); //server accept the client connection request System.out.println(" >> " + "Client No:" + counter + " started!"); ServerClientThread sct = new ServerClientThread(serverClient,counter); //send the request to a separate thread sct.start(); } }catch(Exception e){ System.out.println(e); } } }

Server Client program

This Server Client thread class handled the request independent of any other incoming requests. The following Java program is the part of Multithreaded Server Socket program.

class ServerClientThread extends Thread { Socket serverClient; int clientNo; int squre; ServerClientThread(Socket inSocket,int counter){ serverClient = inSocket; clientNo=counter; } public void run(){ try{ DataInputStream inStream = new DataInputStream(serverClient.getInputStream()); DataOutputStream outStream = new DataOutputStream(serverClient.getOutputStream()); String clientMessage="", serverMessage=""; while(!clientMessage.equals("bye")){ clientMessage=inStream.readUTF(); System.out.println("From Client-" +clientNo+ ": Number is :"+clientMessage); squre = Integer.parseInt(clientMessage) * Integer.parseInt(clientMessage); serverMessage="From Server to Client-" + clientNo + " Square of " + clientMessage + " is " +squre; outStream.writeUTF(serverMessage); outStream.flush(); } inStream.close(); outStream.close(); serverClient.close(); }catch(Exception ex){ System.out.println(ex); }finally{ System.out.println("Client -" + clientNo + " exit!! "); } } }

Client Program

This is the real Client program that request connection to the server. For each Client, you need to open separate console window to run the client program.

import java.net.*; import java.io.*; public class TCPClient { public static void main(String[] args) throws Exception { try{ Socket socket=new Socket("127.0.0.1",8888); DataInputStream inStream=new DataInputStream(socket.getInputStream()); DataOutputStream outStream=new DataOutputStream(socket.getOutputStream()); BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String clientMessage="",serverMessage=""; while(!clientMessage.equals("bye")){ System.out.println("Enter number :"); clientMessage=br.readLine(); outStream.writeUTF(clientMessage); outStream.flush(); serverMessage=inStream.readUTF(); System.out.println(serverMessage); } outStream.close(); outStream.close(); socket.close(); }catch(Exception e){ System.out.println(e); } } }

How to run this program ?

After completing the coding and compilation of the MultithreadedSocketServer, ServerClientThread, and TCPClient programs, the first step is to start the MultithreadedSocketServer program from the command prompt or console window. Upon starting the server program, a message "Server Started..." will be displayed on the console screen where the server program is running.

The next step involves starting the Java TCPClient Socket program on either the same computer or other computers within the same network. When the client program is executed, it establishes a connection to the server and waits for input from the client side. The client program prompts the user to input an integer, which is then sent to the server. The client receives the square of the integer from the server in response. If you wish to test multiple clients, you need to open separate console windows to run each client program. When a client sends the message "bye" from the client side, the server closes the connection with that particular client.

The provided image demonstrates the communication between the server and multiple clients, illustrating the interaction and data exchange between them.

Note: It is important to ensure that the MultithreadedSocketServer program is running before starting the TCPClient program for successful communication between the server and clients.


Multi threaded socket programming in Java

If your Server and Client program running on same machine, then give "127.0.0.1".

Socket socket=new Socket("127.0.0.1",8888);

Otherwise give the IP Address of the machine that MultithreadedSocketServer is running on.

Conclusion

You can implement a multi-threaded client/server architecture using the java.net package and java.util.concurrent package. The server can handle multiple client connections concurrently by creating a new thread for each client, allowing simultaneous communication. The use of threads enables efficient utilization of resources and improved responsiveness in handling multiple client requests.