Why does my chat program only work when both clients are on the same machine?

1.2k views Asked by At

I'm learning some UDP and am creating a Client - Server - Client chat program.

The way it's set up is that the Server runs first, and is always listening for some commands from the clients on port X.

The client, on the other hand, sends commands to the server on port X if it wants to log in or send a message, but it's listening on port Y for incoming packets from the server. The server, of course, sends messages on port Y, as well.

If Client A logs in (first thing user has to do), the server receives the client's username and then gets the client's IP based off of the packet it received, and stores both in a map with the username as the key.

When Client B logs in, the same process happens. Now Client A can send messages to client B (and vice versa), because both their usernames and IPs are stored in the server.

This all works fine when both clients are on the same machine, but once I try to run client B on a different machine, it seems as if the packet never reaches the server. There are no errors, the program doesn't crash, but the server never receives anything.

I tried a bunch of different IPs for the client to send to - one I got from running 'ipconfig' on my command line, another from googling "what is my ip address?", a third IP I got from printing out to the console InetAddress.getLocalHost() - all three of these IPs are different, and none seems to work.

On both machines I went to the firewall and allowed both port X and Y for UDP connections for inbound and outbound activities. This does not seem to help.

Here is my Server code:

    public static void main(String args[]) throws IOException{

        UDPServer SERVER = new UDPServer();

        //calls the run() method
        SERVER.start();
    }

    public UDPServer() throws IOException{

        sock = new DatagramSocket(PORT_NUMBER, InetAddress.getLocalHost());
    }

    public void run(){
        System.out.println("Waiting for Client");
        while(true){

            try{

                //========================================================================================================
                //Prepare the packet to receive data from client
                //========================================================================================================

                //Buffer (byte array) that will receive the client's data
                byte[] buffer = new byte[512];

                //Create a packet using the empty buffer and its length
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

                //========================================================================================================
                //Receive the packet from the client, execute the statement, and get the result
                //========================================================================================================

                //Receive the packet
                sock.receive(packet);
                System.out.println("Server: Received packet from Client");

                //Extract the data
                String fromUser = new String(packet.getData(), 0, packet.getLength());
                //Parse data
                String[] instructions = fromUser.split(separator);

                //Add UserName and IP to tree
                if(instructions[0].equals("LOGIN")){
                    System.out.println("Logged in!");
                    nameIPTree.put(instructions[1], packet.getAddress());

                    run();
                }
                //Send message to recipient and upload to DB
                else if(instructions[0].equals("MESSAGE")){

                    //Create a string composed of the sender and the message
                    String toUser = instructions[1] + separator + instructions[3];

                    //Store the string in the buffer
                    buffer = toUser.getBytes();

                    //Make a new packet with the buffer, its length, the RECEPIENT'S IP (retrieved from tree, hence receiving user HAS TO BE LOGGED IN)
                    //and the port number the server uses

                    int add = 1;

                    packet = new DatagramPacket(buffer, buffer.length, nameIPTree.get(instructions[2]), PORT_NUMBER+add);

                    System.out.println("Sending packet from server to client at packet address: " + packet.getAddress());
                    //Send the packet
                    sock.send(packet);
                    System.out.println("Server: Sent result to Client:  " + toUser);
                }

                }
                catch (IOException /*| ClassNotFoundException | SQLException*/ e){
                    e.printStackTrace();
                    break;
                }
        }
        System.out.println("Closing the socket");
        sock.close();
    }
}

Client code:

    public String TalkToServer(String message){

        try{
            //========================================================================================================
            //Create a datagram socket
            //========================================================================================================
            DatagramSocket sock = new DatagramSocket();

            //========================================================================================================
            //Connect & Send to server
            //========================================================================================================

            //Create a byte array called buffer that will hold the instructions to be sent to the server
            byte[] buffer =  message.getBytes("UTF-8");

            //Get the IP address to which the packet will be sent - this is where the server is
            InetAddress ipAddress = InetAddress.getByName("123.456.78.9");//here is where I tried the different IPs;

            //Create a datagram packet which is composed of the buffer (message), its length, the IP address, 
            //and the port (matches with server's listening port) to send the data on
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, ipAddress, PORT_NUMBER);

//I know these if statements do the same - it was for testing purposes
            if(message.substring(0, 5).equals("LOGIN")){

                System.out.println("Client: Logging in");

                System.out.println("Packet's address is: " + packet.getAddress());
                //Send the packet
                sock.send(packet);
                System.out.println("Client: Sent packet to Server\nSent: " + message);

                sock.close();
                return null;
            }
            if(message.substring(0, 7).equals("MESSAGE")){

                System.out.println("Client: Sending message to server");

                //Send the packet
                sock.send(packet);
                System.out.println("Client: Sent packet to Server\nSent: " + message);

                sock.close();
                return null;
            }
        }
        catch(IOException e){System.out.print(e);}
        return null;
    }
}

And here is the client listener that's in my Main class:

    public MainGUI() throws SocketException, UnknownHostException{


        sock = new DatagramSocket(PORT_NUMBER+1, InetAddress.getLocalHost());
        System.out.println("Client listening on ip: " + InetAddress.getLocalHost());
    }
    public void run(){

        while(true){
            try {

                byte[] buffer =  new byte[512];
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

                sock.receive(packet);
                String fromUser = new String(packet.getData(), 0, packet.getLength());
                //Parse data
                String[] instructions = fromUser.split(separator);
                txtAreaConvo.append(instructions[0] + ":\t" + instructions[1]+"\n\n");


            } catch (IOException e) {   e.printStackTrace();    }

        }

}

Any help at this point would be wildly appreciated!!!

Thanks in advance,

Jona

1

There are 1 answers

7
David.Jones On BEST ANSWER

Whenever I do socket programming, my first step is to get the packet communication working. I use a basic client - server implementation and simply send "Hello World", back and forth to make sure that I can run everything separately (not localhost). You may want to take a step-back from implementing the overall program and try to get the communication working before proceeding. This will probably show where your bug lies. With that being said, i'll try to guess where your problems are:

If your client - server communication is working, until you change to a different IP, then I would have to assume, like you did, that your are giving the wrong IP address/port number. Make sure the client are sending to the port X that the server is listening on. I suspect this isn't your problem; your problem is probably the IP you are giving. whatismyip.com, will give you your public IP address (the IP address you should use if your client is on a different network), ifconfig will give you your local IP Address, i.e. 192.168.X.X (the IP address you should use if the client is using the same network).

All in all, I would use my first suggestion. Take a step-back, and get a bare-basic server-client communication working before trying to solve your overall goal. If you need some basic client-server programs check out Java Socket Programing Examples. Once you get these working, I would continue onto solving your overall goal. This will help you narrow down your problem, and probably solve it.