Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Server class and Client class for a custom chatroom in Java

Explanation of my Program

I have created a chat room server using Java that consists of 3 classes, a server class, a user class and a chat room class. I have also created a client class to interact with the Server. The server creates a user object every time a client connects to the server. Each user object keeps track of the chatrooms the user is in and runs a thread that listens for user input. A server object loops through each chatroom to see if it has been used in the last week.

The Problem

I'm wondering how to actually make a connection to my server with a client object. Currently I open two instances of eclipse. I run my server program in one, and my client program in the other, but I receive nothing in the console of either, which should happen because the server should send information to the client, which the client would then display on the console. The person on the client end could then give input that the client would take and send to the server.

I'm wondering why nothing is happening right now, and what improvements I can make.


Main Files

Server.java

    /*
     * Creates a server that can host up to 10 clients who can join chat rooms, post messages in chatrooms, and view posts made by other clients within the same chat room
     */
    public class Server implements Runnable{
    	protected ArrayList<User> userList;	//A list of users, where each user is a client connected to the server
    	protected LinkedList<Chatroom> chatRooms;	//A list of chatrooms where each client can post messages in, where messages can be seen by all clients in the chatroom
    	private ServerSocket serverSocket;	//The socket for the server
    	
    	/*
    	 * Constructor for the server class. Initializes the server attributes,
    	 */
    	public Server() {
    		this.userList = new ArrayList<User>(10);
    		this.chatRooms = new LinkedList<Chatroom>();
    		try {
    			this.serverSocket = new ServerSocket(5000);
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/*
    	 * Creates a new user when a client connects to the server, and starts a user thread
    	 */
    	public void createUser() {
    		try {
    			Socket userSocket = serverSocket.accept();
    			Thread user = new Thread(new User(userSocket, this));
    			user.start();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/*
    	 * Creates a chatroom for clients to interact in
    	 * @param roomName: The name of the chat room to be created
    	 */
    	protected Chatroom createChatRoom(String roomName) {
    		Chatroom room = new Chatroom(roomName);
    		return room;
    	}
    	
    	/*
    	 * Receives messages from clients and performs actions based on the requests of the client
    	 * (non-Javadoc)
    	 * @see java.lang.Thread#run()
    	 */
    	public void run() {
    		long currentTime;
    		while(true) {
    			try {
    				currentTime = System.currentTimeMillis() / 1000;
    				//Loop through each chatroom and check if the chatroom has been used(joined or had a message sent to it) and remove that chatroom if it hasn't been used in a week
    				for (int i = 0; i < chatRooms.size(); i++) {
    					if (currentTime - 604800 >= chatRooms.get(i).dateLastUsed) {
    						chatRooms.remove(i);
    						//Also remove the chatroom from clients lists of chatrooms
    					}
    				}
    				
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}	
    	
    	public static void main(String args[]) {
    		Server server = new Server ();
    		server.run();
    	}
    }

Client.java

    public class Client extends Thread{
    	private String ip = "127.0.0.1";
    	private int port = 5000 ;
    	private Socket socket;
    	private DataInputStream iStream;
    	private DataOutputStream oStream;
    	private String input;
    	
    	public Client() {
    		try {
    			this.socket = new Socket(ip, port);
    			this.iStream = new DataInputStream(socket.getInputStream());
    			this.oStream = new DataOutputStream(socket.getOutputStream());
    		}catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/*
    	 * Sends a message to the user
    	 * @param message: The message to be sent to the user
    	 */
    	protected void send (String message) {
    		try {
    			oStream.writeUTF(message);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/*
    	 * Closes the connection to the client
    	 */
    	protected void close () {
    		try {
    			iStream.close();
    			oStream.close();
    			socket.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/*
    	 * Runs a thread for the client to constantly receive the clients input(non-Javadoc)
    	 * @see java.lang.Thread#run()
    	 */
    	public void run() {
    		try {
    			Scanner reader = new Scanner(System.in);
    			input = iStream.readUTF();
    			String userInput;//Check if there is input from the user
    			while (input != null) {
    				input = iStream.readUTF();
    				System.out.println(input);
    				userInput = reader.next();
    				oStream.writeUTF(userInput);
    			}
    			reader.close();
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	public static void main(String args[]) {
    		Client client = new Client();
    		client.run();
    	}
    
    }

Objects used by Server.java

User.java

    //Each user represents a client that has connected to the server
    public class User implements Runnable{
    	private DataInputStream inputStream;
    	private DataOutputStream outputStream;
    	private Socket socket;
    	private String name;
    	protected LinkedList<Chatroom> chatRooms;
    	private String input;
    	private Server server;
    	
    	/*
    	 * User Constructor, create a user for each client connecting to the server
    	 * @socket The socket that the user will be communicated through
    	 * The client is prompted to create a name for themself, they are they prompted to do an action.
    	 */
    	public User(Socket socket, Server server) {
    		this.socket = socket;
    		this.server = server;
    		try {
    			inputStream = new DataInputStream(socket.getInputStream());
    			outputStream = new DataOutputStream(socket.getOutputStream());
    			outputStream.writeUTF("Enter a name");
    			this.name = inputStream.readUTF();
    			String message = "Create a chatroom: create \nList Chat Rooms: list \n Join Chat Room: join \n Leave Chat Room: Leave";
    			send(message);
    		} catch (IOException e) {	
    		}
    	}
    	
    	/*
    	 * Returns the current amount of chatrooms this user is in
    	 */
    	protected int chatRoomLength () {
    		return this.chatRooms.size();
    	}
    	
    	/*
    	 * Gets the most recent input from the user
    	 */
    	protected String getInput() {
    		return input;
    	}
    	
    	/*
    	 * Puts a user/client in a chatroom
    	 * @param cRoom: The chatroom that the user will join 
    	 */
    	protected void joinRoom (Chatroom cRoom) {
    		chatRooms.add(cRoom);
    	}
    	
    	/*
    	 * Removes a user/client from a chatroom
    	 */
    	protected void leaveRoom (Chatroom c) {
    		chatRooms.removeFirstOccurrence(c);
    	}
    	
    	/*
    	 * Sends a message to the user
    	 * @param message: The message to be sent to the user
    	 */
    	protected void send (String message) {
    		try {
    			outputStream.writeUTF(message);
    		} catch (IOException e) {
    		}
    	}
    	
    	/*
    	 * Closes the connection to the client
    	 */
    	protected void close () {
    		try {
    			inputStream.close();
    			outputStream.close();
    			socket.close();
    		} catch (IOException e) {}
    	}
    	
    	/*
    	 * Runs a thread for the client to constantly receive the clients input(non-Javadoc)
    	 * @see java.lang.Thread#run()
    	 */
    	public void run() {
    		try {
    			input = inputStream.readUTF();	//Check if there is input from the user
    			//if the user has disconnected from the server, remove them from the list
    			if (input == null) {
    				this.close();
    				this.server.userList.remove(this);
    			}else if (input.equals("create")){	//create a chat room
    				this.send("Name the Chatroom");
    				input = this.getInput();
    				Chatroom c = this.server.createChatRoom(input);
    				this.joinRoom(c);
    			}else if (input.equals("list")) {	//List the current chatrooms
    				String rooms = "";
    				for (int j = 0; j< server.chatRooms.size(); j++) {
    					rooms = rooms + server.chatRooms.get(j).getName() + "\n";
    				}
    				this.send(rooms);
    			}else if (input.equals("join")) {	//Join the user to a chat room
    				int end = chatRooms.size();
    				if (end == 0) {
    					this.send("There's currently no chat rooms");
    				}else {	
    					this.send("Which room would you like to join");
    					input = this.getInput();
    					for (int k = 0; k < end; k++) {
    						if (chatRooms.get(k).getName().equals(input)) {
    							Chatroom joinRoom = chatRooms.get(k);
    							this.joinRoom(joinRoom);
    							String message = "Chatroom " + input + " messages. \n";
    							//Print the current messages in the chatroom to the user
    							for (int j = 0; j < joinRoom.messages.size(); j++ ) {
    								message = message + joinRoom.messages.get(j) + "\n";
    							}
    							this.send(message);
    						} else if (k == end - 1) {
    							this.send("There's no chat rooms by that name");
    						}
    					}
    				}
    			}else if (input.equals("leave")) {	//Remove the user from a chatroom
    				int end = this.chatRoomLength();	//if the chatroom list of the user is empty
    				if (end == 0) {
    					this.send("You are not in any Chat Rooms");
    				}else {
    					this.send("Which room would you like to leave");
    					input = this.getInput();
    					
    					for (int m = 0; m < end; m++) {	//find the chatroom by the same name
    						if (this.chatRooms.get(m).getName().equals(input)) {
    							this.chatRooms.remove(m);
    							this.send("Great! You've been removed from" + input);
    						} else if (m == end - 1) {
    							this.send("You're not in a chatroom named" + input);
    						}
    					}
    				}
    			}else {	//All other input is interpreted as a message to be posted in the chatrooms that the user is in
    				int end = this.chatRoomLength();
    				if (end == 0) {
    					this.send("You can't write to any chat rooms because you are not in any");
    				}
    				for (int m = 0; m < end; m++) {	//Add the users message to ALL the chatrooms the user is in
    					Chatroom c = this.chatRooms.get(m);
    					c.addMessage(input);
    					//Send this added message to all the users in this chatroom
    					for (int n = 0; n < c.users.size(); n++) {
    						User u = c.users.get(n);
    						u.send("Chatroom" + c.getName() + ":" + input);
    					}
    				}
    			}
    			
    		}catch (IOException e) {
    		}
    	}
    }

Chatroom.java

    public class Chatroom {
    	private String name;		//Name of the chatroom
    	protected LinkedList<String> messages;	//List of text messages that have been sent by users to the chatroom and are displayed in the chatroom
    	protected long dateLastUsed;		//The last time the chatroom was joined or had a message sent to it
    	protected LinkedList<User> users;	//The clients/users that are currently in the chatroom
    	
    	/*
    	 * Chatroom constructor
    	 * @param name The name of the chatroom, as determined by the user creating it
    	 */
    	public Chatroom(String name) {
    		dateLastUsed = System.currentTimeMillis() / 1000;		//Sent the time that the chatroom was used last to the current UNIX Epoch time
    		messages = new LinkedList<String>();
    		this.name = name;
    	}
    	
    	/* 
    	 * Adds a message into the chatroom
    	 * @param message The message to be added to the chatroom
    	 */
    	protected void addMessage(String message) {
    		messages.add(message);
    		dateLastUsed = System.currentTimeMillis() / 1000;
    	}
    	
    	/*
    	 * Returns the name of the chatroom
    	 * @return String equal to the name of the chatroom
    	 */
    	protected String getName() {
    		return this.name;
    	}
    	
    }
like image 335
Sam Avatar asked Oct 08 '18 23:10

Sam


People also ask

How do I run a client and server on the same machine?

In order to run both client and server applications on the same host you should bind your server socket to localhost (you can actually write "localhost" it's a preserved word or 127.0. 0.1 ) and address it from the client as well. Localhost allways refers to the computer you work on.


1 Answers

First of all, there is no call to createUser() which has the code to accept the socket connection.

Next is this code in run() function,

try {
            Scanner reader = new Scanner(System.in);
            input = iStream.readUTF();
            String userInput;//Check if there is input from the user
            while (input != null) {
                input = iStream.readUTF();
                System.out.println(input);
                userInput = reader.next();
                oStream.writeUTF(userInput);
}

Once the socket is accepted the server prints Enter a name which is stored input, inside the while loop there is another readUTF() call.

The problem with readUTF() call is that it's blocking, ie. if there isn't a writeUTF() call from the server it waits for data.

I solved the problem by the following snippet,

try {
            Scanner reader = new Scanner(System.in);
            String userInput;//Check if there is input from the user
            do {
                input = iStream.readUTF();
                System.out.println(input);
                userInput = reader.next();
                oStream.writeUTF(userInput);
            } while (input != null);
            reader.close();
        }

Even this isn't the optimum solution as it would need Server to write something into the stream every time.

Another solution would be to read and write using different threads that way we would be able to create a full-duplex like chat, unlike this half duplex.

Then there were some NPE due to no initialization of chatRooms LinkedList,

Plus some logical errors like, not adding chatRooms to its List.

Wrong Code:

protected Chatroom createChatRoom(String roomName) {
        Chatroom room = new Chatroom(roomName);
        return room;
    }

Corrected Code:

protected Chatroom createChatRoom(String roomName) {
        Chatroom room = new Chatroom(roomName);
        this.chatRooms.add(room);
        return room;
    } 

The best way to solve all the bugs would be Github and a few contributors :p

like image 170
Jaikanth J Avatar answered Sep 21 '22 05:09

Jaikanth J