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
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;
}
}
}
}