• When a server needs to process requests concurrently, it is necessary to create a thread for each client.
  • The sketch is the following :
    • the "main" server waits for client connections,
    • if the connection is accepted, the main server create a thread and gives it the communication socket returned by accept().
    • the thread can therefore create streams and communicate with its associated client.
  • So, the "main" server is never used to communicate.

 

  • Depend on what must be done to process client requests, thread may share some data.
  • If it is the case, the easiest way is to gather all shared data within a single object, instantiated by the "main" server and given to the thread constructor.
  • In order to be thread-safe, all methods of this single must be protected by a mutex, and thus in Java, declared as synchronized (or with a synchronized block to protect critical instructions).
  • In the following template, we assume that this shared object is an instance of class called ServerData.
  • This class must be written according to the server needs.

 

  • The code of the "main" server:
import java.io.*;
import java.net.*;
 
class ServerTCP {
  private ServerSocket sockConn;
  private int id;
  private ServerData data; // the shared object between threads

  public ServerTCP(int port) throws IOException {
    sockConn = new ServerSocket(port);
    data = new ServerData( ... );
    id = 0;
  }
  public void mainLoop() throws IOException {
    while(true) {
      try {
        Socket sockComm = sockConn.accept();
        id += 1;
        ThreadServer t = new ThreadServer(id, sockComm, data);
        t.start();
      }
      catch(IOException e) { ... }
    }
  }
}

 

  • The code of the threads :
import java.io.*;
import java.net.*;
 
public ServerThread extends Thread {
  private Socket sockComm;
  private int id;
  private ServerData data;
  BufferedReader br; PrintStream ps;
  // other attributes
  public ServerThread(int id, Socket sockComm, ServerData) throws IOException {
    this.id = id;
    this.sockComm = sockComm;
    this.data = data;
    // streams instantiation
    // other attributes initialization
  }
 
  public void run() {
    try {
        requestLoop();
        // close streams
      }
      catch(IOException e) {
        System.out.println("client disconnected");
      }
  }

  public void requestLoop() throws IOException {
      // same as in the basic template
  }

  // methods to process requests, same as in basic template
}