8.4 A Multi-Threaded Client/Server Application


A Multi-Threaded TCP Server

Introduction

In the the section called “The TCP Client/Server” we developed a full client/server application. The server we developed could only handle one connection at a time. It was structured to create a ConnectionHandler object for each conneciton that was made to the server, however, since the DateServer waits for the ConnectionHandler object to deal with the DateClient then it cannot handle any further connections at the same time. You can see this if you run the server and then connect to it with two clients at the same time - the server will refuse the connection as it is busy serving the current client on port 5050 and has not started listening again.

However, the Server has been structured correctly to make it easily threaded by keeping the connection handler separate from the Server. All that has to be done is to make this connection handler (the HandleConnection class) threaded. Once it is threaded the server can create a separate thread for every client that connects, where the thread deals completely with that client. When the client disconnects this thread can finish.

To make the server threaded we can take the ConnectionHandler class from the section called “The TCP Client/Server” and modify it, by making it inherit from the Thread class and over-riding the run() method of the Thread class.

The DateServer has to be modified slightly to create an object of our new ThreadedConnectionHandler class and to call the start(), method rather than calling the thread's run() method directly.

If we do this the ThreadedServer code should look like:



10111213141516171819202122232425262728293031323334
...

public class ThreadedServer
{
    private static int portNumber = 5050;
        
    public static void main(String args[]) {
      ...
        
        // Server is now listening for connections or would not get to this point
        while (listening) // almost infinite loop - loop once for each client request
        {
            Socket clientSocket = null;
            try{
                System.out.println("**. Listening for a connection...");
                clientSocket = serverSocket.accept();
                System.out.println("00. <- Accepted socket connection from a client: ");
                System.out.println(" <- with address: " + clientSocket.getInetAddress().toString());
                System.out.println(" <- and port number: " + clientSocket.getPort());
            }
            catch (IOException e){
                System.out.println("XX. Accept failed: " + portNumber + e);
                listening = false; // end the loop - stop listening for further client requests
            }        
            
            ThreadedConnectionHandler con = new ThreadedConnectionHandler(clientSocket);
            con.start();
            ...
        }
  ...

And the ThreadedConnectionHandler code should look like:

1234567891011121314151617181920212223242526272829303132333435363738
/* The Connection Handler Class - Written by Derek Molloy for the EE402 Module
* See: ee402.eeng.dcu.ie
*/

package ee402;

import java.net.*;
import java.io.*;

public class ThreadedConnectionHandler extends Thread
{
    private Socket clientSocket = null;                                // Client socket object
    private ObjectInputStream is = null;                        // Input stream
    private ObjectOutputStream os = null;                        // Output stream
    private DateTimeService theDateService;
    
        // The constructor for the connection handler
    public ThreadedConnectionHandler(Socket clientSocket) {
        this.clientSocket = clientSocket;
        //Set up a service object to get the current date and time
        theDateService = new DateTimeService();
    }

    // Will eventually be the thread execution method - can't pass the exception back
    public void run() {
         try {
            this.is = new ObjectInputStream(clientSocket.getInputStream());
            this.os = new ObjectOutputStream(clientSocket.getOutputStream());
            while (this.readCommand()) {}
         }
         catch (IOException e)
         {
                System.out.println("XX. There was a problem with the Input/Output Communication:");
            e.printStackTrace();
         }
    }

...


To make it easier for you to see this update, I have placed all the source files here:



These notes are copyright Dr. Derek Molloy, School of Electronic Engineering, Dublin City University, Ireland 2013-present. Please contact him directly before reproducing any of the content in any way.
Comments