Call me Joni Mitchell because quit due to connection loss works on both sides now.

This commit is contained in:
Jonas 2022-04-07 12:29:36 +02:00
parent de69ea27bb
commit faa2b61acb
5 changed files with 45 additions and 17 deletions

View File

@ -6,7 +6,6 @@ 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.Objects; import java.util.Objects;
import java.util.Scanner; import java.util.Scanner;
@ -88,11 +87,12 @@ public class Client {
try { try {
chatMsg = in.readLine(); //todo: maybe if chatMsg = in.readLine(); //todo: maybe if
if (chatMsg != null) { if (chatMsg != null) {
parse(chatMsg); //todo: i think this trows an error BC chatMsg is null if client disconnects parse(chatMsg);
} } else { System.out.println("chatMsg is null");}
} catch (IOException e) { } catch (IOException e) {
//e.printStackTrace(); //e.printStackTrace();
LOGGER.debug("Exception while trying to read message"); LOGGER.debug("Exception while trying to read message");
disconnectFromServer();
} }
} }
@ -102,7 +102,8 @@ public class Client {
} }
/** /**
* Sends a message to the server, as is. * Sends a message to the server, as is. The message has to already be protocol-formatted. ALL
* communication with the server has to happen via this method!
* *
* @param msg the message sent. Should already be protocol-formatted. * @param msg the message sent. Should already be protocol-formatted.
*/ */
@ -114,20 +115,20 @@ public class Client {
} catch (IOException e) { } catch (IOException e) {
//e.printStackTrace(); //e.printStackTrace();
LOGGER.debug("unable to send msg: " + msg); LOGGER.debug("unable to send msg: " + msg);
disconnectFromServer();
} }
} }
/** /**
* parses a received message according to the client protocol. * parses a received message according to the client protocol.
*
* @param msg the message to be parsed. * @param msg the message to be parsed.
*/ */
public void parse(String msg) { public void parse(String msg) {
JClientProtocolParser.parse(msg, this); JClientProtocolParser.parse(msg, this);
} }
public void closeEverything() { public void disconnectFromServer() {
try { try {
if (in != null) { if (in != null) {
in.close(); in.close();

View File

@ -1,7 +1,6 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client; package ch.unibas.dmi.dbis.cs108.multiplayer.client;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig; import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -41,7 +40,7 @@ public class JClientProtocolParser {
System.out.println(msg.substring(6)); System.out.println(msg.substring(6));
break; break;
case "QUITC": case "QUITC":
c.closeEverything(); c.disconnectFromServer();
break; break;
default: default:
System.out.println("Received unknown command"); System.out.println("Received unknown command");

View File

@ -3,6 +3,7 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.server;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig; import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ServerPinger; import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ServerPinger;
import java.io.*; import java.io.*;
import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.util.HashSet; import java.util.HashSet;
import java.util.Scanner; import java.util.Scanner;
@ -17,20 +18,23 @@ public class ClientHandler implements Runnable {
private BufferedWriter out; private BufferedWriter out;
private BufferedReader in; private BufferedReader in;
private Socket socket; private Socket socket;
private InetAddress ip;
private 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<>();
public static HashSet<ClientHandler> disconnectedClients = new HashSet<>(); //todo: implement re-connection
public static HashSet<ClientHandler> lobby = new HashSet<>(); public static HashSet<ClientHandler> lobby = new HashSet<>();
public static HashSet<ClientHandler> ghostClients = new HashSet<>(); public static HashSet<ClientHandler> ghostClients = new HashSet<>();
/** /**
* Implements the login logic in client-server architecture. * Implements the login logic in client-server architecture.
* * @param ip the ip of the client, used for re-connection.
* @param socket the socket on which to make the connection. * @param socket the socket on which to make the connection.
*/ */
public ClientHandler(Socket socket) { public ClientHandler(Socket socket, InetAddress ip) {
try { try {
this.ip = ip;
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())));
@ -87,6 +91,7 @@ public class ClientHandler implements Runnable {
} catch (IOException e) { } catch (IOException e) {
//e.printStackTrace(); //e.printStackTrace();
LOGGER.debug("Exception while trying to read message"); LOGGER.debug("Exception while trying to read message");
removeClientOnConnectionLoss();
break; break;
} }
} }
@ -146,9 +151,10 @@ public class ClientHandler implements Runnable {
} }
} }
/** Sends a given message to client /** Sends a given message to client. The message has to already be protocol-formatted. ALL
* communication with the client has to happen via this method!
* 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. Should already be protocol-formatted.
*/ */
public void sendMsgToClient(String msg) { public void sendMsgToClient(String msg) {
try { try {
@ -159,17 +165,39 @@ public class ClientHandler implements Runnable {
} catch (IOException e) { } catch (IOException e) {
//e.printStackTrace(); //e.printStackTrace();
LOGGER.debug("unable to send msg: " + msg); LOGGER.debug("unable to send msg: " + msg);
removeClientOnConnectionLoss();
} }
} }
/**
* Removes & disconnects the client. To be used if a severe connection loss is detected (i.e. if trying to
* send / receive a message throws an exception, not just if ping-pong detects a connection loss).
* This is very similar to removeClientOnLogout(), however removeClientOnLogout() should only be used for
* regular quitting, since removeClientOnLogout() cannot handle a client with connection loss.
*/
public void removeClientOnConnectionLoss() {
connectedClients.remove(this);
disconnectClient();
broadcastAnnouncement(getClientUserName() + " has left the server due to a connection loss.");
disconnectedClients.add(this);
}
/** /**
* Does exactly what it says on the tin, closes all connections of Client to Server. * Does exactly what it says on the tin, closes all connections of Client to Server and removes
* the client. To be used if the client requests logout or in other "regular" situations. Use
* removeClientOnConnectionLoss() if the client has to be removed due to a connection loss.
*/ */
public void disconnectClient() { public void removeClientOnLogout() {
broadcastAnnouncement(getClientUserName() + " has left the server."); broadcastAnnouncement(getClientUserName() + " has left the server.");
sendMsgToClient("QUITC"); sendMsgToClient("QUITC");
connectedClients.remove(this); connectedClients.remove(this);
disconnectClient();
}
/**
* Closes the client's socket, in, and out.
*/
public void disconnectClient() {
socket = this.getSocket(); socket = this.getSocket();
in = this.getIn(); in = this.getIn();
out = this.getOut(); out = this.getOut();

View File

@ -56,7 +56,7 @@ public class JServerProtocolParser {
break; break;
case "QUITS": case "QUITS":
//safely disconnects the user //safely disconnects the user
h.disconnectClient(); h.removeClientOnLogout();
break; break;
default: default:
System.out.println("Received unknown command"); System.out.println("Received unknown command");

View File

@ -27,10 +27,10 @@ public class Server {
*/ */
public void startServer() { public void startServer() {
try { try {
System.out.println("Port 42069 is open on " + this.serverSocket.getInetAddress()); //TODO: this is always 0.0.0.0 System.out.println("Port 42069 is open.");
while (!serverSocket.isClosed()) { while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept(); Socket socket = serverSocket.accept();
ClientHandler nextClient = new ClientHandler(socket); ClientHandler nextClient = new ClientHandler(socket, socket.getInetAddress());
Thread th = new Thread(nextClient); Thread th = new Thread(nextClient);
connectedClients.add(nextClient); connectedClients.add(nextClient);
th.start(); th.start();