Chat System - Client Unique Usernames

Introduction: This tutorial is the eleventh in my Java Network Programming using KryoNet series, or sixth in creating a chat client and server system, in which we are going to be ensuring that no two clients have the same username. Previous: In the previous tutorial we created a way to circulate any incoming messages to the server to the rest of the clients. The System: We are going to give the user a GUI to interact with the system - to send messages and see the currently connected members of the chat. When a client connects, add them to a list. Send incoming messages to everyone within the client list except the sender - or send them one back saying that it is received, as confirmation. This Tutorial: Instead of just sending one PacketConnect from the client to the server, we are going to loop this until the username is not currently connected to the server through an other client. Packets: First we are going to create two new packets; Username3Req and Username4Res. Request will contain the username to check with the server if the username exists. Res will be sent from the server as a response to the clients request packet stating whether the username is available or not. Req:
  1. package Packets;
  2.  
  3. public class Packet3UsernameReq extends Packet{
  4.         public String username;
  5. }
Res:
  1. package Packets;
  2.  
  3. public class Packet4UsernameRes extends Packet{
  4.         public boolean bool;
  5. }
Copy the packets to both projects Packets packages. Client: Now we want to edit the client to loop the connection and allow username input from the user...
  1. public void connect(Client client) {
  2.         System.out.println("Enter your username for the new chat room... ");
  3.         Scanner userScan = new Scanner(System.in);
  4.         while (true) {
  5.                 String loggedInUsername = userScan.nextLine();
  6.                 Packet3UsernameReq req = new Packet3UsernameReq();
  7.                 req.username = loggedInUsername;
  8.                 client.sendTCP(req);
  9.                 while (!userServerRes) {
  10.                         try {
  11.                                 System.out.println("Sleeping...");
  12.                                 Thread.sleep(500);
  13.                         }catch (Exception ex) {}
  14.                 }
  15.                 System.out.println("+ " + userServerAvailable);
  16.                 if (userServerAvailable) {
  17.                         System.out.println("That username is already taken. Please enter a new one... ");
  18.                         userServerRes = false; //Reset global booleans used for server username response
  19.                 }else{ //false=available
  20.                         System.out.println("Connecting...");
  21.                         Packet1Connect con = new Packet1Connect();
  22.                         con.name = loggedInUsername;
  23.                         client.sendTCP(con);
  24.                         System.out.println("Connected as " + loggedInUsername);
  25.                         userServerRes = false; //Reset global booleans used for server username response
  26.                         break;
  27.                 }
  28.         }
  29. }
In the method we use a couple of global variables, create these under the initial class line...
  1. boolean userServerRes = false;
  2. boolean userServerAvailable = false;
Then in the constructor where we used to have the four lines of PacketConnect (make sure the listener is above this connect call), replace it with running the new method..
  1. connect(client);
This code will loop until the global variables are set correctly where the username is available. We use Thread.sleep(500) to sleep the program for half a second (500ms) while the server response boolean variable in the global scope is false because we do not yet have a response and so we are unable to check whether the username is available or not through the second boolean global variable and we don't want to spam the application with constant running. Server Listener: Now we want to handle the Packet from the server listener. First we make sure we are receiving a username request, then we run a method from our ClientHandler (we create this in a second) to return whether the username exists or not, with that information we reply with a UsernameRes (response) packet...
  1. else if(object instanceof Packet3UsernameReq) {
  2.         Packet3UsernameReq packet = (Packet3UsernameReq) object;
  3.         boolean userExists = clientHandler.userExists(packet.username);
  4.         Packet4UsernameRes resPacket = new Packet4UsernameRes();
  5.         resPacket.bool = userExists;
  6.         connection.sendTCP(resPacket);
  7. }
Client Handler userExists method...
  1. public boolean userExists(String username) {
  2.         // Return true if user Exists, false if the username is available.
  3.         for (CustomClient c : this.clients) {
  4.                 if (c.getUsername().toLowerCase().equals(username.toLowerCase()))
  5.                         return true; // Username exists.
  6.         }
  7.         return false; //Username available.
  8. }
Class Registering: We also need to register the new classes in both the client and server. Put this under the other class registries we have already - TIP: Make sure the client and server registers are in the same order to avoid serialisation errors...
  1. server.getKryo().register(Packet3UsernameReq.class);
  2. server.getKryo().register(Packet4UsernameRes.class);
And:
  1. client.getKryo().register(Packet3UsernameReq.class);
  2. client.getKryo().register(Packet4UsernameRes.class);
Client Listener: Finally we need to create our client listener. This will listen out for the username response packet and set the global variables accordingly which in turn will trigger the connect while loop to break (stop sleeping for 500ms) and continue with the attempted login...
  1. else if(object instanceof Packet4UsernameRes) {
  2.         Packet4UsernameRes res = (Packet4UsernameRes) object;
  3.         userServerAvailable = res.bool; //Original bool is false if username is available, revert this to true for the variable.
  4.         userServerRes = true;
  5.         System.out.println("Username response received.");
  6. }

Add new comment