I'm working on a simple Java chat program, mostly to learn about UDP and how computers talk with one another.
So far I have been able to set up the server to listen for the clients to connect to it, and I'm even able to redirect the messages from one client to another though the server - that is to say:
Client A --> Server --> Client B
I've gotten to the point where the server actually sends the packet (sock.send(packet)), but the catch is that the clients don't actually "know" to listen. They just know how to send to the server.
I tried setting up a run() for the client, similar to what I have with the server, but as soon as I pull up two clients my program crashes because I'm trying to listen on the same port.
Server code (Please ignore all the separator stuff, it's just a way I'm using to send different pieces of information for now):
package com.jona.chat.UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.sql.SQLException;
import java.util.TreeMap;
public class UDPServer extends Thread{
final int PORT_NUMBER = 4447;
private String separator = "~!~--//1337"; //IGNORE THIS
protected DatagramSocket sock = null;
private TreeMap<String,InetAddress> nameIPTree = new TreeMap<String,InetAddress>(); //IGNORE THIS
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);
}
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); //IGNORE THIS
//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[2] + 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
packet = new DatagramPacket(buffer, buffer.length, nameIPTree.get(instructions[2]), PORT_NUMBER+1);
//Send the packet
sock.send(packet);
System.out.println("Server: Sent result to Client: " + toUser);
}
}
catch (IOException e){
e.printStackTrace();
break;
}
}
System.out.println("Closing the socket");
sock.close();
}
}
Client Side
public class UDPClient extends Thread{
final int PORT_NUMBER = 4447;
private String separator = "~!~--//1337";
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
InetAddress ipAddress = InetAddress.getByName("123.45.67");
//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);
//same thing in both ifs, I know, I just wanted to see what it was doing
if(message.substring(0, 5).equals("LOGIN")){
System.out.println("Client: Logging in");
//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 finally, here is the way I tried to get the client to listen (this is in my main class):
public static void main(String[] args) throws SocketException{
MainGUI listener = new MainGUI();
listener.start();
...
public MainGUI() throws SocketException{
sock = new DatagramSocket(PORT_NUMBER+1);
}
public void run(){
byte[] buffer = new byte[512];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
sock.receive(packet);
String fromUser = new String(packet.getData(), 0, packet.getLength());
//Parse data
String[] instructions = fromUser.split(separator);
System.out.println("Received message: " + instructions[1] + " from " + instructions[0]);
} catch (IOException e) { e.printStackTrace(); }
}
Here is the error I get when I try to run two Mains simultaneously (this error makes sense to me for the most part, I just don't know what else to do to get the client to listen):
Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.bind0(Unknown Source)
at java.net.AbstractPlainDatagramSocketImpl.bind(Unknown Source)
at java.net.DatagramSocket.bind(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at com.jona.chat.UDP.UDPServer.<init>(UDPServer.java:28)
at com.jona.chat.UDP.UDPServer.main(UDPServer.java:20)
Thanks in advance for any help!
You can't run two listeners on the same port on a single machine/network interface. I offer this solution, which should be good enough to run a server and multiple clients on the same machine.