diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/BudaLogConfig.java b/src/main/java/ch/unibas/dmi/dbis/cs108/BudaLogConfig.java index 12bb126..4788f5a 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/BudaLogConfig.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/BudaLogConfig.java @@ -16,7 +16,7 @@ public class BudaLogConfig { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); - loggerConfig.setLevel(Level.TRACE); // change level here + loggerConfig.setLevel(Level.DEBUG); // change level here ctx.updateLoggers(); // This causes all Loggers to refetch information from their LoggerConfig. } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java index 06c3587..6be5fde 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java @@ -6,6 +6,7 @@ import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ClientPinger; import java.net.Socket; import java.io.*; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.Scanner; import org.apache.logging.log4j.LogManager; @@ -27,14 +28,9 @@ public class Client { this.socket = socket; this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); this.in = new BufferedReader((new InputStreamReader((socket.getInputStream())))); - - //TODO add the system based generated username here. - //TODO hide connecting logik(next 4 lines) this.userName = userName; - this.out.write(getUsername()); - this.out.newLine(); - this.out.flush(); - clientPinger = new ClientPinger(this.out, this.socket); + sendMsgToServer(getUsername()); + clientPinger = new ClientPinger(this, this.socket); } catch (IOException e) { e.printStackTrace(); closeEverything(socket, in, out); @@ -44,20 +40,19 @@ public class Client { /** * Sends a message to the Server in a formatted way COMND$msg */ - public void sendMessage() { - try { - Scanner sc = new Scanner(System.in); - while (socket.isConnected()) { - String msg = sc.nextLine(); - String formattedMSG = MessageFormatter.formatMsg(msg); - out.write(formattedMSG); - out.newLine(); - out.flush(); + public void userInputListener() { + new Thread(new Runnable() { + @Override + public void run() { + Scanner sc = new Scanner(System.in); + while (socket.isConnected() && !socket.isClosed()) { + String msg = sc.nextLine(); + String formattedMSG = MessageFormatter.formatMsg(msg); + sendMsgToServer(formattedMSG); + } + LOGGER.debug("userInputListener is done"); } - } catch (IOException e) { - e.printStackTrace(); - closeEverything(socket, in, out); - } + }).start(); } @@ -74,16 +69,19 @@ public class Client { String chatMsg; - while (socket.isConnected()) { + while (socket.isConnected() && !socket.isClosed()) { try { chatMsg = in.readLine(); - parse(chatMsg); + if (chatMsg != null) { + parse(chatMsg); //todo: i think this trows an error BC chatMsg is null if client disconnects + } } catch (IOException e) { e.printStackTrace(); closeEverything(socket, in, out); } } + LOGGER.debug("chatListener is done"); } }).start(); } @@ -152,7 +150,7 @@ public class Client { client.chatListener(); Thread cP = new Thread(client.clientPinger); cP.start(); - client.sendMessage(); //this one blocks. + client.userInputListener(); //this one blocks. } catch (UnknownHostException e) { System.out.println("Invalid host IP"); } catch (IOException e) { diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/JClientProtocolParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/JClientProtocolParser.java index 935fe90..e725058 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/JClientProtocolParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/JClientProtocolParser.java @@ -38,6 +38,9 @@ public class JClientProtocolParser { */ System.out.println(msg.substring(6)); break; + case "QUITC": + //c.closeEverything(); todo: this line. + System.out.println("bye!"); default: System.out.println("Received unknown command"); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java index 7f21ba3..379ecb8 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java @@ -19,16 +19,20 @@ public class MessageFormatter { public static String formatMsg(String msg) { String header = ""; //header is first two characters StringBuilder stringBuilder = new StringBuilder(); - String s; // just a friendly helper to save message in + String s = ""; // just a friendly helper to save message in try { header = msg.substring(0, 2); } catch (IndexOutOfBoundsException e) { - e.printStackTrace(); + header = ""; } switch (header) { case "/c": stringBuilder.append("CHATA$"); - s = msg.substring(3); + try { + s = msg.substring(3); + } catch (Exception e) { + System.out.println("You didn't even write a chat line, you silly billy!"); + } break; case "/q": stringBuilder.append("QUITS$"); @@ -36,7 +40,11 @@ public class MessageFormatter { break; case "/n": stringBuilder.append("NAMEC$"); - s = msg.substring(3); + try { + s = msg.substring(3); + } catch (Exception e) { + System.out.println("Well what do you want your name to be?"); + } break; default: s = msg; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ClientPinger.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ClientPinger.java index f955428..0606c36 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ClientPinger.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ClientPinger.java @@ -1,6 +1,7 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.helpers; import ch.unibas.dmi.dbis.cs108.BudaLogConfig; +import ch.unibas.dmi.dbis.cs108.multiplayer.client.Client; import java.io.BufferedWriter; import java.io.IOException; import java.net.Socket; @@ -18,19 +19,17 @@ public class ClientPinger implements Runnable { private boolean gotPingBack; //should be set to true when client gets a pingback. private boolean isConnected; //set to true unless the ClientPinger detects a connection loss. - BufferedWriter out; //the output of this client through which the pings are sent - private Socket socket; + private final Client client; + private final Socket socket; /** * @param socket the socket the Client is connected to which is used to end the thread if the * connection is lost. - * - * @param out the output through which the pings are sent. */ - public ClientPinger(BufferedWriter out, Socket socket) { + public ClientPinger(Client client, Socket socket) { gotPingBack = false; isConnected = true; - this.out = out; + this.client = client; this.socket = socket; } @@ -38,11 +37,9 @@ public class ClientPinger implements Runnable { public void run() { try { Thread.sleep(2000); - while (socket.isConnected()) { + while (socket.isConnected() && !socket.isClosed()) { gotPingBack = false; - out.write("CPING"); - out.newLine(); - out.flush(); + client.sendMsgToServer("CPING"); Thread.sleep(4000); if (gotPingBack) { if (!isConnected) { //if !isConnected, then the connection had been lost before. @@ -56,8 +53,8 @@ public class ClientPinger implements Runnable { } } } - isConnected = false; //in case the socket accidentally disconnects (can this happen?) - } catch (InterruptedException | IOException e) { + isConnected = false; + } catch (InterruptedException e) { e.printStackTrace(); } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.txt b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.txt index c3c9013..8fa2229 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.txt +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.txt @@ -2,7 +2,10 @@ Client commands: Implemented: * CHATA$message Send chat message to all - * QUITS quit server/ leave server + * QUITS request to quit server/ leave server. The server should then remove the + relevant ClientHandler and close the sockets, but before doing so, it sends + "QUITC" to the client to confirm the quitting. The client doesn't close any + sockets until receiving "QUITC" * CPING Ping from client to server. * PINGB Pingback from client to server. * NAMEC$name Change name to whatever is specified @@ -22,6 +25,7 @@ Server Commands: Implemented: * SPING Ping from server to client * PINGB Pingback from client to server. + * QUITC Confirms to the client that they are being disconnected from the server. Future / planned: * MSGRS "Message received": Paramaters: a string detailing to the client that and what the server received as command. diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ServerPinger.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ServerPinger.java index 5ed80ac..058cf7c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ServerPinger.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/ServerPinger.java @@ -38,9 +38,9 @@ public class ServerPinger implements Runnable { public void run() { try { Thread.sleep(2000); - while (socket.isConnected()) { + while (socket.isConnected() && !socket.isClosed()) { gotPingBack = false; - out.write("SPING"); + out.write("SPING"); //todo: throws exception when client disconnects. out.newLine(); out.flush(); Thread.sleep(4000); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java index b309c67..cbb0936 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java @@ -17,6 +17,7 @@ public class ClientHandler implements Runnable { private BufferedWriter out; private BufferedReader in; private Socket socket; + private Scanner sc; public ServerPinger serverPinger; public static HashSet connectedClients = new HashSet<>(); @@ -44,10 +45,9 @@ public class ClientHandler implements Runnable { serverPinger = new ServerPinger(out, socket); Thread sP = new Thread(serverPinger); sP.start(); - broadcastMessage("SERVER: " + clientUserName + " has joined the Server"); + broadcastChatMessage("SERVER: " + clientUserName + " has joined the Server"); } catch (IOException e) { e.printStackTrace(); - closeEverything(socket, in, out); } } @@ -87,13 +87,12 @@ public class ClientHandler implements Runnable { **/ public void run() { String msg; - while (socket.isConnected()) { + while (socket.isConnected() && !socket.isClosed()) { try { msg = in.readLine(); //todo: here is where the server throws an exception when the client quits JServerProtocolParser.parse(msg, this); } catch (IOException e) { e.printStackTrace(); - closeEverything(socket, in, out); break; } } @@ -116,7 +115,7 @@ public class ClientHandler implements Runnable { String h = this.clientUserName; //just a friendly little helper this.clientUserName = newName; AllClientNames.allNames(newName); - broadcastMessage(h + " have changed their nickname to " + clientUserName); + broadcastChatMessage(h + " have changed their nickname to " + clientUserName); } /** @@ -124,10 +123,9 @@ public class ClientHandler implements Runnable { * * @param msg the Message to be broadcasted */ - - public void broadcastMessage(String msg) { + public void broadcastChatMessage(String msg) { for (ClientHandler client : connectedClients) { - client.sendMsgToClient("CHATM:" + clientUserName + ": \"" + msg + "\""); + client.sendMsgToClient("CHATM$" + clientUserName + ": \"" + msg + "\""); } } @@ -135,9 +133,9 @@ public class ClientHandler implements Runnable { * todo: check for exception if out is closed. * @param msg the given message */ - public void sendMsgToClient(String msg) { try { + //todo: socket closed handling out.write(msg); out.newLine(); out.flush(); @@ -150,8 +148,8 @@ public class ClientHandler implements Runnable { * Does what it sounds like */ public void removeClientHandler() { + broadcastChatMessage("SERVER: " + clientUserName + " has left the server"); connectedClients.remove(this); - broadcastMessage("SERVER: " + clientUserName + " has left the server"); } /** @@ -161,9 +159,14 @@ public class ClientHandler implements Runnable { * @param in the in-Stream reader to be closed * @param out the out-Stream Write to be closed */ - public void closeEverything(Socket socket, BufferedReader in, BufferedWriter out) { + public void disconnectClient() { + sendMsgToClient("QUITC"); removeClientHandler(); + socket = this.getSocket(); + in = this.getIn(); + out = this.getOut(); try { + Thread.sleep(100); if (in != null) { in.close(); } @@ -173,12 +176,10 @@ public class ClientHandler implements Runnable { if (socket != null) { socket.close(); } - } catch (IOException e) { + } catch (IOException | InterruptedException e) { e.printStackTrace(); } } - public void decodeMsg(String msg) { - } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java index 74a0f4d..cc5072f 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java @@ -30,7 +30,7 @@ public class JServerProtocolParser { switch (header) { case CHATA: //sends chat message to all connected clients - h.broadcastMessage(msg.substring(6)); + h.broadcastChatMessage(msg.substring(6)); break; case "NAMEC": //changes name to whatever follows NAMEC$. If the new name is already in use, it will append @@ -47,7 +47,7 @@ public class JServerProtocolParser { break; case "QUITS": //safely disconnects the user - h.closeEverything(h.getSocket(), h.getIn(), h.getOut()); + h.disconnectClient(); break; default: System.out.println("Received unknown command");