complete overhaul of client / server communication. Several methods renamed, tweaked protocol.

This commit is contained in:
Jonas 2022-04-02 17:10:29 +02:00
parent 52a6a0cd65
commit f677f5cb71
9 changed files with 70 additions and 59 deletions

View File

@ -16,7 +16,7 @@ public class BudaLogConfig {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration(); Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); 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. ctx.updateLoggers(); // This causes all Loggers to refetch information from their LoggerConfig.
} }

View File

@ -6,6 +6,7 @@ import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ClientPinger;
import java.net.Socket; import java.net.Socket;
import java.io.*; import java.io.*;
import java.net.SocketException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Scanner; import java.util.Scanner;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -27,14 +28,9 @@ public class Client {
this.socket = socket; this.socket = socket;
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream())))); 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.userName = userName;
this.out.write(getUsername()); sendMsgToServer(getUsername());
this.out.newLine(); clientPinger = new ClientPinger(this, this.socket);
this.out.flush();
clientPinger = new ClientPinger(this.out, this.socket);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
closeEverything(socket, in, out); closeEverything(socket, in, out);
@ -44,20 +40,19 @@ public class Client {
/** /**
* Sends a message to the Server in a formatted way COMND$msg * Sends a message to the Server in a formatted way COMND$msg
*/ */
public void sendMessage() { public void userInputListener() {
try { new Thread(new Runnable() {
@Override
public void run() {
Scanner sc = new Scanner(System.in); Scanner sc = new Scanner(System.in);
while (socket.isConnected()) { while (socket.isConnected() && !socket.isClosed()) {
String msg = sc.nextLine(); String msg = sc.nextLine();
String formattedMSG = MessageFormatter.formatMsg(msg); String formattedMSG = MessageFormatter.formatMsg(msg);
out.write(formattedMSG); sendMsgToServer(formattedMSG);
out.newLine();
out.flush();
} }
} catch (IOException e) { LOGGER.debug("userInputListener is done");
e.printStackTrace();
closeEverything(socket, in, out);
} }
}).start();
} }
@ -74,16 +69,19 @@ public class Client {
String chatMsg; String chatMsg;
while (socket.isConnected()) { while (socket.isConnected() && !socket.isClosed()) {
try { try {
chatMsg = in.readLine(); 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) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
closeEverything(socket, in, out); closeEverything(socket, in, out);
} }
} }
LOGGER.debug("chatListener is done");
} }
}).start(); }).start();
} }
@ -152,7 +150,7 @@ public class Client {
client.chatListener(); client.chatListener();
Thread cP = new Thread(client.clientPinger); Thread cP = new Thread(client.clientPinger);
cP.start(); cP.start();
client.sendMessage(); //this one blocks. client.userInputListener(); //this one blocks.
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
System.out.println("Invalid host IP"); System.out.println("Invalid host IP");
} catch (IOException e) { } catch (IOException e) {

View File

@ -38,6 +38,9 @@ public class JClientProtocolParser {
*/ */
System.out.println(msg.substring(6)); System.out.println(msg.substring(6));
break; break;
case "QUITC":
//c.closeEverything(); todo: this line.
System.out.println("bye!");
default: default:
System.out.println("Received unknown command"); System.out.println("Received unknown command");
} }

View File

@ -19,16 +19,20 @@ public class MessageFormatter {
public static String formatMsg(String msg) { public static String formatMsg(String msg) {
String header = ""; //header is first two characters String header = ""; //header is first two characters
StringBuilder stringBuilder = new StringBuilder(); 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 { try {
header = msg.substring(0, 2); header = msg.substring(0, 2);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
e.printStackTrace(); header = "";
} }
switch (header) { switch (header) {
case "/c": case "/c":
stringBuilder.append("CHATA$"); stringBuilder.append("CHATA$");
try {
s = msg.substring(3); s = msg.substring(3);
} catch (Exception e) {
System.out.println("You didn't even write a chat line, you silly billy!");
}
break; break;
case "/q": case "/q":
stringBuilder.append("QUITS$"); stringBuilder.append("QUITS$");
@ -36,7 +40,11 @@ public class MessageFormatter {
break; break;
case "/n": case "/n":
stringBuilder.append("NAMEC$"); stringBuilder.append("NAMEC$");
try {
s = msg.substring(3); s = msg.substring(3);
} catch (Exception e) {
System.out.println("Well what do you want your name to be?");
}
break; break;
default: default:
s = msg; s = msg;

View File

@ -1,6 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.helpers; package ch.unibas.dmi.dbis.cs108.multiplayer.helpers;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig; import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.Client;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; 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 gotPingBack; //should be set to true when client gets a pingback.
private boolean isConnected; //set to true unless the ClientPinger detects a connection loss. 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 final Client client;
private Socket socket; private final Socket socket;
/** /**
* @param socket the socket the Client is connected to which is used to end the thread if the * @param socket the socket the Client is connected to which is used to end the thread if the
* connection is lost. * 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; gotPingBack = false;
isConnected = true; isConnected = true;
this.out = out; this.client = client;
this.socket = socket; this.socket = socket;
} }
@ -38,11 +37,9 @@ public class ClientPinger implements Runnable {
public void run() { public void run() {
try { try {
Thread.sleep(2000); Thread.sleep(2000);
while (socket.isConnected()) { while (socket.isConnected() && !socket.isClosed()) {
gotPingBack = false; gotPingBack = false;
out.write("CPING"); client.sendMsgToServer("CPING");
out.newLine();
out.flush();
Thread.sleep(4000); Thread.sleep(4000);
if (gotPingBack) { if (gotPingBack) {
if (!isConnected) { //if !isConnected, then the connection had been lost before. 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?) isConnected = false;
} catch (InterruptedException | IOException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@ -2,7 +2,10 @@ Client commands:
Implemented: Implemented:
* CHATA$message Send chat message to all * 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. * CPING Ping from client to server.
* PINGB Pingback from client to server. * PINGB Pingback from client to server.
* NAMEC$name Change name to whatever is specified * NAMEC$name Change name to whatever is specified
@ -22,6 +25,7 @@ Server Commands:
Implemented: Implemented:
* SPING Ping from server to client * SPING Ping from server to client
* PINGB Pingback from client to server. * PINGB Pingback from client to server.
* QUITC Confirms to the client that they are being disconnected from the server.
Future / planned: Future / planned:
* MSGRS "Message received": Paramaters: a string detailing to the client that and what the server received as command. * MSGRS "Message received": Paramaters: a string detailing to the client that and what the server received as command.

View File

@ -38,9 +38,9 @@ public class ServerPinger implements Runnable {
public void run() { public void run() {
try { try {
Thread.sleep(2000); Thread.sleep(2000);
while (socket.isConnected()) { while (socket.isConnected() && !socket.isClosed()) {
gotPingBack = false; gotPingBack = false;
out.write("SPING"); out.write("SPING"); //todo: throws exception when client disconnects.
out.newLine(); out.newLine();
out.flush(); out.flush();
Thread.sleep(4000); Thread.sleep(4000);

View File

@ -17,6 +17,7 @@ public class ClientHandler implements Runnable {
private BufferedWriter out; private BufferedWriter out;
private BufferedReader in; private BufferedReader in;
private Socket socket; private Socket socket;
private
Scanner sc; Scanner sc;
public ServerPinger serverPinger; public ServerPinger serverPinger;
public static HashSet<ClientHandler> connectedClients = new HashSet<>(); public static HashSet<ClientHandler> connectedClients = new HashSet<>();
@ -44,10 +45,9 @@ public class ClientHandler implements Runnable {
serverPinger = new ServerPinger(out, socket); serverPinger = new ServerPinger(out, socket);
Thread sP = new Thread(serverPinger); Thread sP = new Thread(serverPinger);
sP.start(); sP.start();
broadcastMessage("SERVER: " + clientUserName + " has joined the Server"); broadcastChatMessage("SERVER: " + clientUserName + " has joined the Server");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
closeEverything(socket, in, out);
} }
} }
@ -87,13 +87,12 @@ public class ClientHandler implements Runnable {
**/ **/
public void run() { public void run() {
String msg; String msg;
while (socket.isConnected()) { while (socket.isConnected() && !socket.isClosed()) {
try { try {
msg = in.readLine(); //todo: here is where the server throws an exception when the client quits msg = in.readLine(); //todo: here is where the server throws an exception when the client quits
JServerProtocolParser.parse(msg, this); JServerProtocolParser.parse(msg, this);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
closeEverything(socket, in, out);
break; break;
} }
} }
@ -116,7 +115,7 @@ public class ClientHandler implements Runnable {
String h = this.clientUserName; //just a friendly little helper String h = this.clientUserName; //just a friendly little helper
this.clientUserName = newName; this.clientUserName = newName;
AllClientNames.allNames(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 * @param msg the Message to be broadcasted
*/ */
public void broadcastChatMessage(String msg) {
public void broadcastMessage(String msg) {
for (ClientHandler client : connectedClients) { 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. * todo: check for exception if out is closed.
* @param msg the given message * @param msg the given message
*/ */
public void sendMsgToClient(String msg) { public void sendMsgToClient(String msg) {
try { try {
//todo: socket closed handling
out.write(msg); out.write(msg);
out.newLine(); out.newLine();
out.flush(); out.flush();
@ -150,8 +148,8 @@ public class ClientHandler implements Runnable {
* Does what it sounds like * Does what it sounds like
*/ */
public void removeClientHandler() { public void removeClientHandler() {
broadcastChatMessage("SERVER: " + clientUserName + " has left the server");
connectedClients.remove(this); 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 in the in-Stream reader to be closed
* @param out the out-Stream Write 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(); removeClientHandler();
socket = this.getSocket();
in = this.getIn();
out = this.getOut();
try { try {
Thread.sleep(100);
if (in != null) { if (in != null) {
in.close(); in.close();
} }
@ -173,12 +176,10 @@ public class ClientHandler implements Runnable {
if (socket != null) { if (socket != null) {
socket.close(); socket.close();
} }
} catch (IOException e) { } catch (IOException | InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public void decodeMsg(String msg) {
} }
}

View File

@ -30,7 +30,7 @@ public class JServerProtocolParser {
switch (header) { switch (header) {
case CHATA: case CHATA:
//sends chat message to all connected clients //sends chat message to all connected clients
h.broadcastMessage(msg.substring(6)); h.broadcastChatMessage(msg.substring(6));
break; break;
case "NAMEC": case "NAMEC":
//changes name to whatever follows NAMEC$. If the new name is already in use, it will append //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; break;
case "QUITS": case "QUITS":
//safely disconnects the user //safely disconnects the user
h.closeEverything(h.getSocket(), h.getIn(), h.getOut()); h.disconnectClient();
break; break;
default: default:
System.out.println("Received unknown command"); System.out.println("Received unknown command");