From e807b563901efb1fa0548bcfa708a6ad426acf47 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 26 Mar 2020 19:48:32 +0100 Subject: [PATCH] Client-Server communication done --- .../.idea/$PRODUCT_WORKSPACE_FILE$ | 19 ++ specs/zaccariach-NR09/.idea/.gitignore | 2 + specs/zaccariach-NR09/.idea/compiler.xml | 13 ++ specs/zaccariach-NR09/.idea/misc.xml | 14 ++ specs/zaccariach-NR09/.idea/vcs.xml | 6 + specs/zaccariach-NR09/PROTOCOL.md | 36 ++++ specs/zaccariach-NR09/pom.xml | 67 +++++++ .../main/java/client/ApplicationClient.java | 31 +++ .../src/main/java/client/Client.java | 131 +++++++++++++ .../src/main/java/protocol/Protocol.java | 15 ++ .../main/java/server/ApplicationServer.java | 15 ++ .../src/main/java/server/Server.java | 181 ++++++++++++++++++ specs/zaccariach-NR09/zaccariach-NR09.iml | 2 + 13 files changed, 532 insertions(+) create mode 100644 specs/zaccariach-NR09/.idea/$PRODUCT_WORKSPACE_FILE$ create mode 100644 specs/zaccariach-NR09/.idea/.gitignore create mode 100644 specs/zaccariach-NR09/.idea/compiler.xml create mode 100644 specs/zaccariach-NR09/.idea/misc.xml create mode 100644 specs/zaccariach-NR09/.idea/vcs.xml create mode 100644 specs/zaccariach-NR09/PROTOCOL.md create mode 100644 specs/zaccariach-NR09/pom.xml create mode 100644 specs/zaccariach-NR09/src/main/java/client/ApplicationClient.java create mode 100644 specs/zaccariach-NR09/src/main/java/client/Client.java create mode 100644 specs/zaccariach-NR09/src/main/java/protocol/Protocol.java create mode 100644 specs/zaccariach-NR09/src/main/java/server/ApplicationServer.java create mode 100644 specs/zaccariach-NR09/src/main/java/server/Server.java create mode 100644 specs/zaccariach-NR09/zaccariach-NR09.iml diff --git a/specs/zaccariach-NR09/.idea/$PRODUCT_WORKSPACE_FILE$ b/specs/zaccariach-NR09/.idea/$PRODUCT_WORKSPACE_FILE$ new file mode 100644 index 0000000..79be354 --- /dev/null +++ b/specs/zaccariach-NR09/.idea/$PRODUCT_WORKSPACE_FILE$ @@ -0,0 +1,19 @@ + + + + + + + 11 + + + + + + + + \ No newline at end of file diff --git a/specs/zaccariach-NR09/.idea/.gitignore b/specs/zaccariach-NR09/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/specs/zaccariach-NR09/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/specs/zaccariach-NR09/.idea/compiler.xml b/specs/zaccariach-NR09/.idea/compiler.xml new file mode 100644 index 0000000..f365e58 --- /dev/null +++ b/specs/zaccariach-NR09/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/specs/zaccariach-NR09/.idea/misc.xml b/specs/zaccariach-NR09/.idea/misc.xml new file mode 100644 index 0000000..d24ea8e --- /dev/null +++ b/specs/zaccariach-NR09/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/specs/zaccariach-NR09/.idea/vcs.xml b/specs/zaccariach-NR09/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/specs/zaccariach-NR09/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/specs/zaccariach-NR09/PROTOCOL.md b/specs/zaccariach-NR09/PROTOCOL.md new file mode 100644 index 0000000..5c530d6 --- /dev/null +++ b/specs/zaccariach-NR09/PROTOCOL.md @@ -0,0 +1,36 @@ +# Exercise Protocol Design - Phase 1 + Auteur : Christian Zaccaria & Nenad Rajic + Date : 18.03.2020 + +## What transport protocol do we use? +TCP +## How does the client find the server (addresses and ports)? + +Le port est fixé à 3385 et actuellement uniquement par localhost + +## Who speaks first? +Le serveur en proposant les différentes actions au client. + +## What is the sequence of messages exchanged by the client and the server? (flow) + +Le serveur initie la communication et envoie la liste des actions proposées. En cas d'erreur, le serveur notifie le client afin de pouvoir retaper sa commande. + +## What happens when a message is received from the other party? (semantics) + +Client : Lit le résultat. + +Serveur : Calcul des 2 opérandes et envoi du résultat. + +## What is the syntax of the messages? How we generate and parse them? (syntax) + +Serveur envoi la liste des différentes commandes possible (String) + +Client répond : [_OPERANDE NOMBRE1 NOMBRE2_] + +Serveur récupére le resultat, le parse, effectue le calcul et re-envoie le résultat sous forme : [_RESULTAT_] + +Le split de chaque information s'effectue au niveau des _WHITESPACES_. + +## Who closes the connection and when? + +Le client peut arrêter la connexion avec _STOP_. Quand au serveur il reste en écoute tout le temps afin de pouvoir directement intitié la connexion avec d'autres clients. \ No newline at end of file diff --git a/specs/zaccariach-NR09/pom.xml b/specs/zaccariach-NR09/pom.xml new file mode 100644 index 0000000..7e14f13 --- /dev/null +++ b/specs/zaccariach-NR09/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + zaccariach-NR09 + zaccariach-NR09 + 1.0-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 7 + 7 + + + 3.8.1 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.1 + + + package + + shade + + + + + + tales.Story + + + + + + + + + + + diff --git a/specs/zaccariach-NR09/src/main/java/client/ApplicationClient.java b/specs/zaccariach-NR09/src/main/java/client/ApplicationClient.java new file mode 100644 index 0000000..3c66c89 --- /dev/null +++ b/specs/zaccariach-NR09/src/main/java/client/ApplicationClient.java @@ -0,0 +1,31 @@ +/** + * Authors : Christian Zaccaria & Nenad Rajic + * Date 26.03.2020 + * Exercice Protocol-Design + * File : ApplicationClient.java + */ +package client; + +import protocol.Protocol; + +import java.util.Scanner; + +public class ApplicationClient { + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + Client client = new Client(); + String request = ""; + client.connect(args[0], Protocol.DEFAULT_PORT, "User"); + boolean closeConnection = false; + do{ + request = sc.nextLine(); + //If user wants to stop connection + if(request.compareTo("STOP") == 0){ + closeConnection = true; + } + client.calculate(request); + }while(!closeConnection); + client.disconnect(); + } +} diff --git a/specs/zaccariach-NR09/src/main/java/client/Client.java b/specs/zaccariach-NR09/src/main/java/client/Client.java new file mode 100644 index 0000000..10fbd1c --- /dev/null +++ b/specs/zaccariach-NR09/src/main/java/client/Client.java @@ -0,0 +1,131 @@ +/** + * Authors : Christian Zaccaria & Nenad Rajic + * Date 26.03.2020 + * Exercice Protocol-Design + * File : Client.java + */ +package client; + +import protocol.Protocol; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Client { + + final static Logger LOG = Logger.getLogger(Client.class.getName()); + + private int defaultPort; + + /** + * Constructor of Client class, define the default port + */ + public Client(){ + defaultPort = Protocol.DEFAULT_PORT; + } + + Socket clientSocket = null; + BufferedReader reader = null; + PrintWriter writer = null; + boolean connected = false; + String userName; + + /** + * This inner class implements the Runnable interface, so that the run() + * method can execute on its own thread. This method reads data sent from the + * server, line by line, until the connection is closed or lost. + */ + class NotificationListener implements Runnable { + + @Override + public void run() { + String notification; + try { + while ((connected && (notification = reader.readLine()) != null)) { + LOG.log(Level.INFO, "Server notification for {1}: {0}", new Object[]{notification,userName}); + } + } catch (IOException e) { + LOG.log(Level.SEVERE, "Connection problem in client used by {1}: {0}", new Object[]{e.getMessage(),userName}); + connected = false; + } finally { + cleanup(); + } + } + } + + + /** + * This method is used to connect to the server and to inform the server that + * the user "behind" the client has a name (in other words, the HELLO command + * is issued after successful connection). + * + * @param serverAddress the IP address used by the Presence Server + * @param serverPort the port used by the Presence Server + */ + public void connect(String serverAddress, int serverPort, String userName) { + try { + clientSocket = new Socket(serverAddress, serverPort); + reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + writer = new PrintWriter(clientSocket.getOutputStream()); + connected = true; + this.userName = userName; + } catch (IOException e) { + LOG.log(Level.SEVERE, "Unable to connect to server: {0}", e.getMessage()); + cleanup(); + return; + } + // Let us start a thread, so that we can listen for server notifications + new Thread(new NotificationListener()).start(); + + } + + /** + * Request to calculate + * @param request + */ + public void calculate(String request){ + writer.println(request); + writer.flush(); + } + + /** + * Disconnection with the server + */ + public void disconnect() { + LOG.log(Level.INFO, "{0} has requested to be disconnected.", userName); + connected = false; + writer.println("BYE"); + cleanup(); + } + + /** + * Clean all stuff used to conmmunicate with the server + */ + private void cleanup() { + + try { + if (reader != null) { + reader.close(); + } + } catch (IOException ex) { + LOG.log(Level.SEVERE, ex.getMessage(), ex); + } + + if (writer != null) { + writer.close(); + } + + try { + if (clientSocket != null) { + clientSocket.close(); + } + } catch (IOException ex) { + LOG.log(Level.SEVERE, ex.getMessage(), ex); + } + } +} \ No newline at end of file diff --git a/specs/zaccariach-NR09/src/main/java/protocol/Protocol.java b/specs/zaccariach-NR09/src/main/java/protocol/Protocol.java new file mode 100644 index 0000000..7217d5a --- /dev/null +++ b/specs/zaccariach-NR09/src/main/java/protocol/Protocol.java @@ -0,0 +1,15 @@ +/** + * Authors : Christian Zaccaria & Nenad Rajic + * Date 26.03.2020 + * Exercice Protocol-Design + * File : Protocol.java + */ +package protocol; + +public class Protocol { + public static final String ADD = "ADD"; + public static final String SUB = "SUB"; + public static final String MULTI = "MULTIPLY"; + public static final String DIVIDE = "DIV"; + public static final int DEFAULT_PORT = 3385; +} diff --git a/specs/zaccariach-NR09/src/main/java/server/ApplicationServer.java b/specs/zaccariach-NR09/src/main/java/server/ApplicationServer.java new file mode 100644 index 0000000..53fd457 --- /dev/null +++ b/specs/zaccariach-NR09/src/main/java/server/ApplicationServer.java @@ -0,0 +1,15 @@ +/** + * Authors : Christian Zaccaria & Nenad Rajic + * Date 26.03.2020 + * Exercice Protocol-Design + * File : ApplicationServer.java + */ +package server; + +public class ApplicationServer { + + public static void main(String[] args){ + Server server = new Server(); + server.start(); + } +} diff --git a/specs/zaccariach-NR09/src/main/java/server/Server.java b/specs/zaccariach-NR09/src/main/java/server/Server.java new file mode 100644 index 0000000..8c31684 --- /dev/null +++ b/specs/zaccariach-NR09/src/main/java/server/Server.java @@ -0,0 +1,181 @@ +/** + * Authors : Christian Zaccaria & Nenad Rajic + * Date 26.03.2020 + * Exercice Protocol-Design + * File : Server.java + */ +package server; + +import protocol.Protocol; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Server { + final static Logger LOG = Logger.getLogger(Server.class.getName()); + + private int defaultPort; + + /** + * Constructor of Server class, define the default port + */ + public Server(){ + defaultPort = Protocol.DEFAULT_PORT; + } + + /** + * Start whole of engine for the server + */ + public void start(){ + LOG.info("Starting server..."); + + ServerSocket serverSocket; + Socket clientSocket = null; + BufferedReader reader = null; + PrintWriter writer = null; + boolean run = true; + + try{ + LOG.log(Level.INFO, "Try to starting socket server"); + serverSocket = new ServerSocket(defaultPort); + logServerSocketAddress(serverSocket); + } catch (IOException ex){ + LOG.log(Level.SEVERE, null, ex); + return; + } + + while(true){ + try{ + LOG.log(Level.INFO, "Waiting for connection with client on port " + defaultPort); + clientSocket = serverSocket.accept(); + logSocketAddress(clientSocket); + + LOG.log(Level.INFO, "Connect a reader and writer"); + reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + writer = new PrintWriter(clientSocket.getOutputStream()); + + LOG.log(Level.INFO, "Waiting for communication"); + String line; + + writer.write("Welcome to the calculator ! Please choose an operation ADD / SUB / MULTIPLY / DIV [number1] [number2] \n"); + writer.write("If you want to stop to calcule enter STOP \n"); + writer.flush(); + + LOG.log(Level.INFO,"Listen and process client request"); + + while((line = reader.readLine()) != null && run){ + String[] tokens = line.split(" "); + String operation = tokens[0]; + + if(tokens.length != 3){ + if(tokens[0] == "STOP"){ + run = false; + break; + }else{ + writer.write("Too many /few arguments"); + writer.flush(); + } + continue; + } + + if((!isNumerical(tokens[1]) || (!isNumerical(tokens[2])))){ + writer.println("Error, insert only numbers to calculate"); + writer.flush(); + continue; + } + + switch(operation){ + case(Protocol.ADD): + writer.println("Result of " + tokens[1] + " + " + tokens[2] + " = " + (Double.parseDouble(tokens[1]) + Double.parseDouble(tokens[2]))); + break; + case (Protocol.SUB): + writer.println("Result of " + tokens[1] + " - " + tokens[2] + " = " + (Double.parseDouble(tokens[1]) - Double.parseDouble(tokens[2]))); + break; + case (Protocol.MULTI): + writer.println("Result of " + tokens[1] + " * " + tokens[2] + " = " + (Double.parseDouble(tokens[1]) * Double.parseDouble(tokens[2]))); + break; + case(Protocol.DIVIDE): + writer.println(Double.parseDouble(tokens[2]) != 0 ? "Result of " + tokens[1] + " / " + tokens[2] + " = " + + (Double.parseDouble(tokens[1]) / Double.parseDouble(tokens[2])) : "Error : cannot divide by 0"); + break; + default: + writer.println("Error, request is not an ADD / SUB / MULTIPLY / DIV operation"); + break; + } + writer.flush(); + + } + + LOG.log(Level.INFO,"Cleaning ressources..."); + clientSocket.close(); + reader.close(); + writer.close(); + + } catch (IOException ex){ + if(reader != null){ + try{ + reader.close(); + } catch (IOException ex1){ + LOG.log(Level.SEVERE, ex1.getMessage(), ex1); + } + } + if(writer != null){ + writer.close(); + } + if(clientSocket != null){ + try { + clientSocket.close(); + } catch (IOException ex1){ + LOG.log(Level.SEVERE, ex1.getMessage(), ex1); + } + } + LOG.log(Level.SEVERE, ex.getMessage(), ex); + } + } + } + + /** + * Check if can transform a string to a number + * @param line String to convert to number + * @return true if he can convert, false if he cannot + */ + private boolean isNumerical(String line) { + try{ + Double.parseDouble(line); + }catch(NumberFormatException format){ + return false; + } + return true; + } + + /** + * A utility method to print server socket information + * + * @param serverSocket the socket that we want to log + */ + private void logServerSocketAddress(ServerSocket serverSocket) { + LOG.log(Level.INFO, " Local IP address: {0}", new Object[]{serverSocket.getLocalSocketAddress()}); + LOG.log(Level.INFO, " Local port: {0}", new Object[]{Integer.toString(serverSocket.getLocalPort())}); + LOG.log(Level.INFO, " is bound: {0}", new Object[]{serverSocket.isBound()}); + } + + /** + * A utility method to print socket information + * + * @param clientSocket the socket that we want to log + */ + private void logSocketAddress(Socket clientSocket) { + LOG.log(Level.INFO, " Local IP address: {0}", new Object[]{clientSocket.getLocalAddress()}); + LOG.log(Level.INFO, " Local port: {0}", new Object[]{Integer.toString(clientSocket.getLocalPort())}); + LOG.log(Level.INFO, " Remote Socket address: {0}", new Object[]{clientSocket.getRemoteSocketAddress()}); + LOG.log(Level.INFO, " Remote port: {0}", new Object[]{Integer.toString(clientSocket.getPort())}); + } +} + + diff --git a/specs/zaccariach-NR09/zaccariach-NR09.iml b/specs/zaccariach-NR09/zaccariach-NR09.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/specs/zaccariach-NR09/zaccariach-NR09.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file