1°/ Server with a single client at a time

Some assumptions :

  • the protocol is based on text data, more precisely exchanging only lines of text.
  • the format of all request to the server is : req_identifier client_id param1 param2 ...
  • the identifier of each request is a REQ1, REQ2, ... except the "quit" request that means the client wants to disconnect from the server.
  • the client id is a unique identifier that is sent to the client juste after the acception of the connection.

 

In order to have a readable code, the server is divided in 2 classes:  Server and ServerTCP. The first one is the execution entry point, and the second one is the "real" server

Server.java :

import java.net.*;
import java.io.*;
 
class Server {
 
  public static void usage() {
    System.err.println("usage : java Server port");
    System.exit(1);
  }
 
  public static void main(String[] args) {
 
    if (args.length != 1) {
      usage();
    }
 
    ServerTCP server = null;
    try {
      int port = Integer.parseInt(args[0]);
      server = new ServerTCP(port);
      server.mainLoop();
    }
    catch(NumberFormatException e) {
      System.err.println("invalid port number");
      System.exit(1);
    }
    catch(IOException e) {
      System.err.println("cannot communicate with client");
      System.exit(1);
    }
  }
}

 

 ServerTCP.java :

import java.io.*;
import java.net.*;
import java.util.*;
 
class ServerTCP  {
 
  BufferedReader br; 
  PrintStream ps;
  ServerSocket sockConn;
  Socket sockComm;
  int idClient;
  // other attributes, usefull to process request
 
  public ServerTCP(int port) throws IOException {
    idClient = 0;
    sockConn = new ServerSocket(port);
  }
 
  public void mainLoop() throws IOException {
    while(true) {
      sockComm = sockConn.accept();
      try {
        br = new BufferedReader(new InputStreamReader(sockComm.getInputStream()));
        ps = new PrintStream(sockComm.getOutputStream());
        idClient += 1;
        ps.println(idClient); // sending its id to the client
        requestLoop();
        br.close(); // close stream => close connection
        ps.close();
      }
      catch(IOException e) {
        System.out.println("client disconnected");
      }
    }
  }
 
  public void requestLoop() throws IOException {
 
    String req = "";
    boolean stop = false;
 
    while(!stop) {
      req = br.readLine();
      if (req == null) return; // stop loop : suppose that client disconnected
      if (req.isEmpty()) continue; // empty req => do nothing special
      String[] reqParts = req.split(" ");
      // check if client id is correct
      int id;
      try {
        id = Integer.parseInt(reqParts[1]);
      }
      catch(NumberFormatException e) { 
        ps.println("ERR invalid type of parameter");
        continue; // go directly to start of while loop
      }
      if (id != idClient) {
        ps.println("ERR invalid id");
        continue; // go directly to start of while loop
      }

      if ("REQ1".equals(reqParts[0])) {
        if (reqParts.length != ...) { // check number of params
          ps.println("ERR invalid number of paramters");
        }
        else {
          processRequest1( ... ); // replace ... by a list of reqParts[x]
        }
      }
      else if ("REQ2".equals(reqParts[0])) {
        if (reqParts.length != ...) {
          ps.println("ERR invalid number of parameters");
        }
        else {
          processRequest2( ... ); // replace ... by a list of reqParts[x]
        }
      }
      /* etc. with other requests */
      else if ("quit".equals(lst[0])) {
        stop = true;
      }
    }
  }  
 
  public void processRequest1(String param1, String param2, ...) throws IOException {
    try {
      // add here some params to translate into numbers
    }
    catch(NumberFormatException e) { 
      ps.println("ERR invalid type of parameter");
      return; 
    }

    // add here other tests on other parameters
 
    // if all ok, 
    ps.println("OK");
    // process the request and send the result to the client
  }
 
  // etc. with other processRequestX() methods
}
 

2°/ Interactive client in a console

  • This client executes within a terminal, and the requests are given by the user via the keyboard.
  • From user's point of view, sending a request consists in typing a line that represents what he wants to ask to the server. In the followng template, the line format for the user is : request_name param1 param2 ... (NB : it is quite similar to the format of the real request that is sent by the client, see below)
  • Here again, the client application is organized in 2 classes:  Client and ClientTCP
Client.java :
import java.net.*;
import java.io.*;
 
class Client {
 
  public static void usage() {
    System.err.println("usage : java Client ip_server port");
    System.exit(1);
  }
 
  public static void main(String[] args) {
 
    if (args.length != 2) {
      usage();
    }
 
    ClientTCP client = null;
    try {
      int port = Integer.parseInt(args[1]);
      client = new ClientTCP(args[0], port);
      client.requestLoop();
    }
    catch(NumberFormatException e) {
      System.err.println("invalid port number");
      System.exit(1); 
    }
    catch(IOException e) {
      System.err.println("cannot communicate with server");
      System.exit(1);
    }
  }
}

 

ClientTCP.java

import java.io.*;
import java.net.*;
import java.util.*;
 
class ClientTCP  {
 
  Socket sockComm;
  BufferedReader br; PrintStream ps;
  String id; // the client id sent by the server with request 0
 
  public ClientTCP(String serverIp, int serverPort) throws IOException {
    sockComm = new Socket(serverIp, serverPort);
    ps = new PrintStream(sockComm.getOutputStream());
    br = new BufferedReader(new InputStreamReader(sockComm.getInputStream()));
    // get my id
    id = br.readLine();
  }
 
  public void requestLoop() throws IOException { 
 
    boolean stop = false;
    String reqLine = null;
    BufferedReader consoleIn = null;
    String[] reqParts = null;
 
    consoleIn = new BufferedReader(new InputStreamReader(System.in));
 
    while (!stop) {
      System.out.print("Client> ");
      reqLine = consoleIn.readLine();
      reqParts = reqLine.split(" ");
 
      if ("req1".equals(reqParts[0])) {
        String req = "REQ1 "+id+" ";
        // adding to req parameters obtined from reqParts[1] reqParts[2], ...)
        ps.println(req);
        String answer = br.readLine();
        // processing answer
      }
      else if ("req2".equals(reqParts[0])) {
        String req = "REQ2 "+id+ " ";
        // adding to req parameters obtained from reqParts[1] reqParts[2], ...)
        ps.println(req);
        String answer = br.readLine();
        // processing answer
      }
      /* etc. with other requests */
       else if ("quit".equals(reqParts[0])) {
        ps.println("quit");
        stop = true;
      }
    }
  }
}