3 Replies - 9531 Views - Last Post: 02 May 2014 - 03:07 PM Rate Topic: -----

#1 Algorithm518   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 2
  • Joined: 01-May 14

Java Client/Server Chat Room with P2P?

Posted 02 May 2014 - 01:26 AM

I've been experimenting with code I found from a older topic posted on these forums. The original post can be found with this link.

I'm modifying the code to implement a different functionality.

[Goal]
  • Host a server where clients with unique usernames can connect. [DONE]
  • Request a private chat with another client connected to the server by prompting them. [DONE]
  • If accepted, the two users will chat only between themselves and not through the server.


The modified code below shows the method request() in Server.java at Line 86 that shows my attempt so far. When I attempt to get the response from the target client, it just hangs there regardless of the target's actions.

How can I obtain a response from the target client for use in the computation?
How could I create a connection between the clients only?

This is a challenge to myself as I am new to concurrency and networking. The main idea of my implementation is that the server is like a phone directory. Both clients are listed in the directory and both can make a call to each other. They use the server as a medium to find the information (address,port) in respect to the name. Once that information is known, a line can be established and no longer have a use for the directory (server).

What are some modifications I can utilize to solve these issues without a full code overhaul?

*I apologize upfront for any sloppy code. My priority is functionality over efficiency at the moment.

Server.java
/* Server.java */
import java.net.*;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;

// The Server
public class Server {
    private static int uniqueID;
    private ArrayList<ClientThread> clientList; //Keep track of all clients
    private SimpleDateFormat theDate; //For displaying time and date
    private int port; //The port to listen on
    private boolean control; //Decides whether to keep going
    
    //Constructor that is given a specified port
    public Server(int port) {
        this.port = port; //Set the port
        theDate = new SimpleDateFormat("h:mma"); //Set the time
        clientList = new ArrayList<ClientThread>();
    }
    
    //Start the connection
    public void start() {
        control = true;
        //Create the socket and wait for a client to request
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            
            //Loop forever to listen for client requests
            while(control){
                display("Server is listening for Clients on port " + port + ".");
                Socket socket = serverSocket.accept(); //Pause and wait for connection
                
                //If listening has stopped
                if(!control) break;
                ClientThread newThread = new ClientThread(socket);
                clientList.add(newThread);
                newThread.start(); 
               
            }
            //Closing the server down due to break in loop
            try {
                serverSocket.close();
                for(int i = 0; i < clientList.size(); i++) {
                    ClientThread temp = clientList.get(i);
                    try {
                        temp.Input.close();
                        temp.Output.close();
                        temp.socket.close();
                    }
                    catch(IOException IOe){
                        //For safety
                    }
                }
            }
            catch(Exception e) {
                display ("Closing the Server and Clients: " + e);
            }
                    
        }
        catch (IOException e) {
            String message = theDate.format(new Date()) + " Error on new ServerSocket: " + e + "\n";
                display(message);
        }
    }
    
    //Display an event to the console (Server Only)
    private void display(String prompt) {
        String time = theDate.format(new Date()) + " " + prompt;
            System.out.println(time);
    }
    
    private synchronized void broadcast(String message) {
        String time = theDate.format(new Date());
        String toSend = time + " " + message;
        System.out.println(toSend);
        for(int i = clientList.size(); --i >= 0;) {
            ClientThread temp = clientList.get(i);
            if(!temp.writeMsg(toSend)){
                clientList.remove(i);
                display("Disconnected Client " + temp.username + " removed from list.");
            }
        }
    }
    
    private void request(String source, String target){
        ClientThread origin = null;
        //Find the ClientThread of the Soruce
        for(int i = 0; i < clientList.size(); i++) {
           origin = clientList.get(i);
           //If the Source was found
           if(origin.username.equalsIgnoreCase(source)){
               break;
            }
        }
    
        // Find the ClientThread of the Target
        for(int i = 0; i < clientList.size(); i++) {
            ClientThread destination = clientList.get(i);
            //If the target was found
            if(destination.username.equalsIgnoreCase(target)){
                destination.Output.println(source + " has requested a chat with you. Accept(Y/N)?");
                System.out.println("Attempting to read...");
                try{
                String answer = destination.Input.readLine(); //This is where the program hangs
                }catch(IOException e){
                    System.out.println("Exception on reading from target: " + e);
                }
                //destination.beingRequested = true;
                //Loop until response found
//                while(true){
//                    if(destination.requestResponse != null){
//                        if(destination.requestResponse.equalsIgnoreCase("Y")){
//                            destination.Output.println("Connection Established.");
//                            origin.Output.println("Connection Accepted.");
//                            break;
//                        }else if (destination.requestResponse.equalsIgnoreCase("N")){
//                            break;
//                        }
//                    }
//                }
                System.out.println("Reading done.");
                break;
            }
        }
        
        
    }
    
    //For removing a client who requested LOGOUT
    synchronized void remove(int id) {
        for(int i = 0; i < clientList.size(); i++) {
            ClientThread temp = clientList.get(i);
            //It was found
            if(temp.id == id) {
                clientList.remove(i);
                return;
            }
        }
    }
    
    public static void main(String[] args){
        int portNumber = (5000 + 31) + 128 * 0; //Listen on this port
        //Create a new Server and start it
        Server server = new Server(portNumber);
        server.start();
    }
    
    //Threads for each instance of a client
    class ClientThread extends Thread {
        Socket socket; // The listening/talk socket connection
        BufferedReader Input;
        PrintWriter Output;
        int id; //Unique ID
        String username; //Username
        String date;
        String Address;
        int Port;
        Boolean duplicate = false; //Duplicate flag
        Boolean beingRequested = false; //A client is attempting to connect
        String requestResponse = null; //Client's response to request
        
        //Constructor
        ClientThread(Socket socket) {
            id = ++uniqueID;
            this.socket = socket;
            //Create the data streams
            System.out.println("Thread is attempting to create Data Streams.");
            try {
                Output = new PrintWriter(socket.getOutputStream(),true);
                Input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                Address = socket.getInetAddress().toString();
                Port = socket.getPort();
                System.out.println("Address is: " + Address);
                System.out.println("Port is: " + Port);
                        
                // Read the username
                while(true){
                    username = Input.readLine();
                    for(int i = 0; i < clientList.size(); i++){
                        if(username.equalsIgnoreCase(clientList.get(i).username)) {
                                duplicate = true;
                        }
                    }
                    if(!duplicate) break;
                    display("Username conflict detected.");
                    Output.println("false");
                    writeMsg("[SERVER] Username " + username + " is already taken. Please enter another.");
                    duplicate = false; //Reset the boolean to check the new username given
                }
                Output.println("true");
                display(username + " just connected.");
            }
            catch (IOException e) {
                    display("Exception creating new Input/output Streams: " + e);
                    return;
            }
            date = new Date().toString();
        }
        
        //Run this forever, read and broadcast
        public void run() {
            boolean keepGoing = true;
            String found = null;
            while(keepGoing) {
                try {
                    found = Input.readLine();
                    if(beingRequested == true && 
                            (found.equalsIgnoreCase("Y") || found.equalsIgnoreCase("N"))){
                        requestResponse = found;
                    }
                }
                catch (IOException e) {
                    display(username + " Exception reading Stream: " + e);
                    break;
                }
                //Parse the message recieved from the client
                String[] separated = found.split(" ");
                if(separated[0].equalsIgnoreCase("Request")){
                    if(separated.length == 2){
                        writeMsg("[SERVER] Contacting " + separated[1] + " . . .");
                        request(username, separated[1]);
                    }else {
                        Output.println("[SERVER] Correct usage is <request [username]>");
                    }
                }else if(separated[0].equalsIgnoreCase("LOGOUT") && separated.length == 1){
                        display(username + " has disconnected from the Server.");
                        keepGoing = false;
                }else if(separated[0].equalsIgnoreCase("WHO") && separated.length == 1){
                    for(int i = 0; i < clientList.size(); ++i) {
                        ClientThread eachClient = clientList.get(i);
                        writeMsg((i+1) + ") " + eachClient.username + " since " + eachClient.date);
                    }
                }else { 
                    //broadcast(username + ": " + found);
                }
            }
            //Clean up the user list
            remove(id);
            close();
        }
        
        // try to close everything
        private void close() {
                // try to close the connection
                try {
                        if(Output != null) Output.close();
                }
                catch(Exception e) {}
                try {
                        if(Input != null) Input.close();
                }
                catch(Exception e) {};
                try {
                        if(socket != null) socket.close();
                }
                catch (Exception e) {}
        }
        
        // Write the string to the Client Output
        private boolean writeMsg(String toSend) {
            if(!socket.isConnected()){
                close();
                return false;
            }
            Output.println(toSend);
            return true;
        }
        
    }
    
    
}


Client.java
/* Client.java */
import java.net.*;
import java.io.*;
import java.util.*;
 
public class Client {
    //For the I/O
    private BufferedReader Input;
    private PrintWriter Output;
    private Socket socket;

    private String server, username;
    private int port;
    
    Client(String server, int port, String username) {
        this.server = server;
        this.port = port;
        this.username = username;
    }
    
    
    public boolean start() {
        //Attempt to connect to server
        try {
            socket = new Socket(server,port);
        }
        catch(Exception ec){
            display("Error connecting to server: " + ec);
            return false;
        }
        String message = "Connection Accepted " + socket.getInetAddress() + ":" + socket.getPort() + "\n";
        display(message);
        
        //Create the data streams
        try {
            Input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            Output = new PrintWriter(socket.getOutputStream(), true);
        }
        catch(IOException eIO) {
            display("Exception when creating new Streams: " + eIO);
            return false;
        }
        
        //Send the username to the server and check for any issues
        Scanner newUser = new Scanner(System.in);
        try {
            while(true) {
                Output.println(username);
                if(Input.readLine().equalsIgnoreCase("true")) break;
                String conflict = Input.readLine();
                System.out.println(conflict);
                System.out.print("Enter a new username: ");
                username = newUser.next();
            }
        }
        catch (IOException eIO) {
            display("Exception during login : " + eIO);
            disconnect();
            return false;
        }
        new ListenFromServer().start();
        return true;
    }
    
    private void display(String msg) {
        System.out.println(msg);
    }
    
    // Sends a message to the server
    void sendMessage(String msg) {
            Output.println(msg);
    }
    
    // An issue occurs and all streams are closed
    private void disconnect() {
        try { 
                if(Input != null) Input.close();
        }
        catch(Exception e) {} // not much else I can do
        try {
                if(Output != null) Output.close();
        }
        catch(Exception e) {} // not much else I can do
        try{
                if(socket != null) socket.close();
        }
        catch(Exception e) {} // not much else I can do
    }
    
    public static void main(String[] args) {
            // default values
            int portNumber = 1500;
            String serverAddress = "localhost";
            String userName = "Anonymous";
            // Notify the client of the current status
            System.out.println("You are currently offline...");
            System.out.println("\tConnect to the server using <login [username] [portNumber]>");
            //Loop until client connects online
            Scanner r = new Scanner(System.in);
            while(true) {
                System.out.print("> ");
                String buffer = r.nextLine();
                String[] split = buffer.split(" ");
                //Check if the user wants to login
                if(split[0].equalsIgnoreCase("login")) {
                    switch(split.length) {
                            // > login [username] [portNumber]
                            case 3:
                                 try {
                                            portNumber = Integer.parseInt(split[2]);
                                    }
                                    catch(Exception e) {
                                            System.out.println("Invalid port number.");
                                            System.out.println("Usage is: <login [username] [portNumber]>");
                                            return;
                                    }
                                    userName = split[1];
                                break;
                            // > login [username]
                            case 2:
                                    userName = split[1];
                                break;
                            case 1: 
                                    break;
                            case 0:
                                    break;
                            // invalid number of arguments
                            default:
                                    System.out.println("Usage is: <login [username] [portNumber]>");
                            return;
                    }
                   break;
                }
            }
            // create the Client object
            Client client = new Client(serverAddress, portNumber, userName);
            // test if we can start the connection to the Server
            // if it failed nothing we can do
            if(!client.start()){
                return;
            }

            // wait for messages from user
            Scanner scan = new Scanner(System.in);
            // loop forever for message from the user
            while(true) {
                    System.out.print("> ");
                    // read message from user
                    String msg = scan.nextLine();
                    // split for request function
                    String[] request = msg.split(" ");
                    // logout if message is LOGOUT
                    if(msg.equalsIgnoreCase("LOGOUT")){
                        client.sendMessage(msg);
                        break;
                    }
                    client.sendMessage(msg);
            }
            // done disconnect
            client.disconnect();	
    }
    class ListenFromServer extends Thread {
        public void run() {
                while(true) {
                        try {
                                String msg = Input.readLine();
                                System.out.println(msg);
                                System.out.print("> ");
                        }
                        catch(IOException e) {
                                display("Server has closed the connection: " + e);
                                break;
                        }
                }
        }
    }
}



Is This A Good Question/Topic? 1
  • +

Replies To: Java Client/Server Chat Room with P2P?

#2 g00se   User is offline

  • D.I.C Lover
  • member icon

Reputation: 3550
  • View blog
  • Posts: 16,187
  • Joined: 20-September 08

Re: Java Client/Server Chat Room with P2P?

Posted 02 May 2014 - 02:11 AM

I don't have an answer for you as i, like you, don't know what's going on in the code, but the following should help you get on the right road:

a. It's essential for good code to have proper logging in place - particularly where multihreading is involved. If you don't, once your code gets larger, you will find it impossible to know what's going on
b.
        if (origin.username.equalsIgnoreCase(source)) {
            break;
        }


That's OK (though it would be better o be using a Map where you were confident of having allocated unique keys) but not only do you assume that the find was successful but that noone has the same username.
You should make appropriate corrections and then use exactly the same approach with the target, which you're not currently doing.

This post has been edited by g00se: 02 May 2014 - 02:13 AM
Reason for edit:: Clarification

Was This Post Helpful? 0
  • +
  • -

#3 Algorithm518   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 2
  • Joined: 01-May 14

Re: Java Client/Server Chat Room with P2P?

Posted 02 May 2014 - 12:18 PM

Thanks for the reply, I realized that would be an easier alternative to use a map or hashmap. However I suppose my main concern is I don't understand why Line 105 does not execute properly.
Was This Post Helpful? 0
  • +
  • -

#4 g00se   User is offline

  • D.I.C Lover
  • member icon

Reputation: 3550
  • View blog
  • Posts: 16,187
  • Joined: 20-September 08

Re: Java Client/Server Chat Room with P2P?

Posted 02 May 2014 - 03:07 PM

Hanging in comms is usually caused by disorderly treatment of read-write ordering of your protocol. You need to know what is going on and that's a major reason you should have logging in place
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1