Another complete overhaul of client-server communication:
-Added broadcastAnnouncement message to ClientHandler -Bugfix: "Connection lost" at startup -Added LOGIN$username to protocol
This commit is contained in:
parent
51d969e298
commit
c64c754d22
@ -20,16 +20,24 @@ public class Client {
|
||||
private Socket socket;
|
||||
private BufferedReader in;
|
||||
private BufferedWriter out;
|
||||
public String userName;
|
||||
public ClientPinger clientPinger;
|
||||
|
||||
public Client(Socket socket, String userName) {
|
||||
public Client(Socket socket) {
|
||||
try {
|
||||
this.socket = socket;
|
||||
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream()))));
|
||||
this.userName = userName;
|
||||
sendMsgToServer(getUsername()); //todo: dont just send username directly pls
|
||||
|
||||
//sending the initial name to server.
|
||||
String systemName;
|
||||
try {
|
||||
systemName = System.getProperty("user.name");
|
||||
} catch (Exception e) {
|
||||
systemName = "Unknown User";
|
||||
}
|
||||
if (systemName == null) systemName = "Unknown User";
|
||||
sendMsgToServer("LOGON$" + systemName);
|
||||
|
||||
clientPinger = new ClientPinger(this, this.socket);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -53,9 +61,7 @@ public class Client {
|
||||
sendMsgToServer(formattedMSG);
|
||||
}
|
||||
Thread.sleep(20);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//LOGGER.debug("just checked next line");
|
||||
@ -67,12 +73,10 @@ public class Client {
|
||||
|
||||
|
||||
/**
|
||||
* Starts a thread which listens for incoming messages
|
||||
* Starts a thread which listens for incoming chat messages / other messages that the user
|
||||
* has to see
|
||||
*/
|
||||
public void chatListener() {
|
||||
/*TODO: what type of decoding has to be done
|
||||
TODO how shall input be logged?
|
||||
*/
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -144,19 +148,18 @@ public class Client {
|
||||
String hostname;
|
||||
int port = 42069; //can be set via argument later if needed.
|
||||
if (args.length < 1) {
|
||||
System.out.println("Enter the host's IP address (or type localhost)");
|
||||
System.out.println("Enter the host's IP address (or type l for localhost)");
|
||||
hostname = sc.next();
|
||||
if (hostname == "l") {
|
||||
hostname = "localhost";
|
||||
}
|
||||
} else {
|
||||
hostname = args[0];
|
||||
}
|
||||
String systemName = System.getProperty("user.name");
|
||||
System.out.println("Choose a nickname (Suggestion: " + systemName
|
||||
+ "): "); //Suggests a name based on System username
|
||||
String username = sc.next();
|
||||
Socket socket;
|
||||
try {
|
||||
socket = new Socket(hostname, 42069);
|
||||
Client client = new Client(socket, username);
|
||||
Client client = new Client(socket);
|
||||
client.chatListener();
|
||||
Thread cP = new Thread(client.clientPinger);
|
||||
cP.start();
|
||||
@ -169,10 +172,6 @@ public class Client {
|
||||
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public Socket getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
@ -16,11 +16,13 @@ public class JClientProtocolParser {
|
||||
* @param c this Client(required so this method can access the Client's methods)
|
||||
*/
|
||||
public static void parse(String msg, Client c) {
|
||||
//LOGGER.debug("got message: " + msg + ".");
|
||||
String header = ""; //"header" is the first 5 characters, i.e. the protocol part
|
||||
try {
|
||||
header = msg.substring(0, 5);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
System.out.println("Received unknown command");
|
||||
e.printStackTrace();
|
||||
}
|
||||
switch (header) {
|
||||
case "SPING":
|
||||
@ -40,7 +42,7 @@ public class JClientProtocolParser {
|
||||
break;
|
||||
case "QUITC":
|
||||
c.closeEverything();
|
||||
System.out.println("bye!");
|
||||
break;
|
||||
default:
|
||||
System.out.println("Received unknown command");
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ public class ClientPinger implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
Thread.sleep(20000);
|
||||
while (socket.isConnected() && !socket.isClosed()) {
|
||||
gotPingBack = false;
|
||||
client.sendMsgToServer("CPING");
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
Client commands:
|
||||
Client to server commands:
|
||||
|
||||
Implemented:
|
||||
* LOGON$name Log on, with the name set to whatever follow $.
|
||||
* CHATA$message Send chat message to all
|
||||
* 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
|
||||
@ -20,7 +21,7 @@ Future / planned:
|
||||
* VOTEH humans voting who is the ghost
|
||||
* LISTP list players/clients in session with the Server
|
||||
|
||||
Server Commands:
|
||||
Server to client Commands:
|
||||
|
||||
Implemented:
|
||||
* SPING Ping from server to client
|
||||
|
||||
@ -33,19 +33,21 @@ public class ClientHandler implements Runnable {
|
||||
try {
|
||||
this.socket = socket;
|
||||
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream()))));
|
||||
this.clientUserName = in.readLine();
|
||||
// duplicate handling: if username already taken, assign random name to client
|
||||
this.in = new BufferedReader(new InputStreamReader((socket.getInputStream())));
|
||||
this.clientUserName = "Mysterious Passenger"; //todo: duplicate handling for this
|
||||
/*
|
||||
// todo: duplicate handling more elegantly
|
||||
if (AllClientNames.allNames("").contains(clientUserName)) {
|
||||
clientUserName = NameGenerator.randomName(clientUserName);
|
||||
}
|
||||
// add username to list of all client names for future duplicate checking
|
||||
AllClientNames.allNames(clientUserName);
|
||||
|
||||
*/
|
||||
connectedClients.add(this);
|
||||
serverPinger = new ServerPinger(out, socket);
|
||||
Thread sP = new Thread(serverPinger);
|
||||
sP.start();
|
||||
broadcastChatMessage("SERVER: " + clientUserName + " has joined the Server");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -109,23 +111,52 @@ public class ClientHandler implements Runnable {
|
||||
* @param newName The desired new name to replace the old one with.
|
||||
*/
|
||||
public void changeUsername(String newName) {
|
||||
if (AllClientNames.allNames("").contains(newName)) {
|
||||
if (AllClientNames.allNames("").contains(newName)) { //todo: more elegant solution
|
||||
newName = NameGenerator.randomName(newName);
|
||||
}
|
||||
String h = this.clientUserName; //just a friendly little helper
|
||||
this.clientUserName = newName;
|
||||
AllClientNames.allNames(newName);
|
||||
broadcastChatMessage(h + " have changed their nickname to " + clientUserName);
|
||||
broadcastAnnouncement(h + " has changed their nickname to " + clientUserName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a Message to all active clients in the form "Username: msg"
|
||||
* Sets the client's username on login, if the username is already taken, a similar
|
||||
* option is chosen. Functionally, the only difference between this method and changeUsername
|
||||
* is that it doesn't print out the name change.
|
||||
*
|
||||
* @param msg the Message to be broadcasted
|
||||
* @param name The desired name.
|
||||
*/
|
||||
public void setUsernameOnLogin(String name) {
|
||||
//todo: duplicate checking
|
||||
this.clientUserName = name;
|
||||
broadcastAnnouncement( clientUserName + " has joined the Server");
|
||||
//todo: add this name to namelist
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a Message to all active clients in the form "Username: @msg"
|
||||
*
|
||||
* @param msg the Message to be broadcast
|
||||
*/
|
||||
public void broadcastChatMessage(String msg) {
|
||||
for (ClientHandler client : connectedClients) {
|
||||
client.sendMsgToClient("CHATM$" + clientUserName + ": \"" + msg + "\"");
|
||||
client.sendMsgToClient("CHATM$" + clientUserName + ": " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a non-chat Message to all active clients. This can be used for server
|
||||
* messages / announcements rather than chat messages. The message will be printed to the user ex-
|
||||
* actly as it is given to this method. Unlike broadcastChatMessage, it will also be printed onto
|
||||
* the server console.
|
||||
*
|
||||
* @param msg the Message to be broadcast
|
||||
*/
|
||||
public void broadcastAnnouncement(String msg) {
|
||||
System.out.println(msg);
|
||||
for (ClientHandler client : connectedClients) {
|
||||
client.sendMsgToClient("CHATM$" + msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ public class JServerProtocolParser {
|
||||
* @param h this ClientHandler (required so this method can access the ClientHandler's methods)
|
||||
*/
|
||||
public static void parse(String msg, ClientHandler h) {
|
||||
//LOGGER.debug("got message: " + msg + ".");
|
||||
String header = ""; //"header" is the first 5 characters, i.e. the protocol part
|
||||
try {
|
||||
header = msg.substring(0, 5);
|
||||
@ -32,6 +33,14 @@ public class JServerProtocolParser {
|
||||
//sends chat message to all connected clients
|
||||
h.broadcastChatMessage(msg.substring(6));
|
||||
break;
|
||||
case "LOGON":
|
||||
//sets name to whatever follows LOGON$
|
||||
try {
|
||||
h.setUsernameOnLogin(msg.substring(6));
|
||||
} catch (Exception e) {
|
||||
h.setUsernameOnLogin("A Mysterious Passenger");
|
||||
}
|
||||
break;
|
||||
case "NAMEC":
|
||||
//changes name to whatever follows NAMEC$. If the new name is already in use, it will append
|
||||
//random numbers to the name.
|
||||
@ -47,6 +56,7 @@ public class JServerProtocolParser {
|
||||
break;
|
||||
case "QUITS":
|
||||
//safely disconnects the user
|
||||
h.broadcastAnnouncement(h.getClientUserName() + " has left the server.");
|
||||
h.disconnectClient();
|
||||
break;
|
||||
default:
|
||||
|
||||
@ -34,15 +34,6 @@ public class Server {
|
||||
Thread th = new Thread(nextClient);
|
||||
connectedClients.add(nextClient);
|
||||
th.start();
|
||||
// close socket + remove client if client is disconnected
|
||||
/* TODO: Modify or remove this disconnection handling - right now, it is not functioning
|
||||
(when disconnecting there are "broken pipe" exceptions on client side and "stream closed"
|
||||
exceptions on the server side).
|
||||
*/
|
||||
if (nextClient.getSocket().getInputStream().read() == -1) {
|
||||
System.out.println("client disconnected. closing socket");
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
Reference in New Issue
Block a user