I want that my client application is able to connect to a Server application.
The problem is that my Client doesn't know the Server ip (in LAN).
So I tried to use java object MulticastSocket. Luckily Oracle have a page with an example of Broadcasting.
Here I have rearranged it for my use.
Server code:
long FIVE_SECONDS = 5000;
int port = 4445;
DatagramSocket socket = new DatagramSocket(port);
while (true) {
System.out.println("Server running...");
try {
// message for client
String dString = "Hello Client";
byte[] buf = dString.getBytes();
// send
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
socket.send(packet);
// sleep for a while
try {
Thread.sleep((long)(Math.random() * FIVE_SECONDS));
}
catch (InterruptedException e) {
System.err.println("Interrupted Exception");
}
} catch (IOException e) {
System.err.println("IOException");
}
}
Client code:
MulticastSocket socket = new MulticastSocket(4445);
InetAddress address = InetAddress.getByName("230.0.0.1");
socket.joinGroup(address);
// receive the message
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received: " + received);
socket.leaveGroup(address);
socket.close();
When I run Srver: no problem, but when I try running client it throw java.net.BindException: Address already in use cause both client and server are listening/sending information on port 4445.
But isn't it right? To connect each other they must have the same port number, or they'll never 'meet'.
Can I solve this problem? How?
Are the port number correct?
Is this a right resolution to the problem about the unknown server ip?
Thanks!
As Warren mentioned in his answer, your client and server can't bind to the same port on the same machine. The Oracle example is not doing that.
The client should bind to port 4446 and the server should bind to port 4445. When the server create a DatagramPacket it should do so with the client's port which is 4446.
If you do this and the client still can't receive, you may need to set the outgoing interface for multicast on the server. You can do this with either the setInterface or setNetworkInterface methods.
For example, suppose your serverhas IP addresses 192.168.1.1 and 192.168.2.1. If you want your sender to send from 192.168.1.1, you would call:
multicastSocket.setInterface(InetAddress.getByName("192.168.1.1"));
You are getting this exception because you are trying to run your server application and your client application on the same machine. When you start your client, your server has already bound to port 4445, so it is already in use - and thus unavailable - when your client tries to bind to it.
Running your server and your client on different machines would get around that particular error. However, you could also get around it by choosing different ports for your server and your client.
For example if you ran your server on port 4445, and your client on port 4446, you could do the following. On the server, you would add a variable for the client port, and use the client port as the destination port when sending your DatagramPacket:
int clientPort = 4446;
...
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, clientPort);
instead of
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
On the client, you would simply bind to the client port instead of the server port:
MulticastSocket socket = new MulticastSocket(4446);
instead of
MulticastSocket socket = new MulticastSocket(4445);
Using different port numbers for the server and for the client would allow you to run both the server application and the client application on the same machine and get you past this particular issue.
Related
Here is my setup: On my home network a server is running on port SERVER_PORT. A port forwarding rule has been added to the router such that all incoming connections to SERVER_PORT will reach the server's machine. Somewhere else on the internet there exists a client who tries to send a UDP packet to the server and receive a packet back.
The server will receive the connection on SERVER_PORT but will send a packet back from a socket bound to a different (random) port.
The idea is emulating a listener socket just like the one used for TCP, and for each new connection allocating a new socket.
I have tested my program with clients that are connected to my home network, and outside the home network (cellular). The program didn't work either way.
The program does work though if I send a packet back using the server's original socket (the one that is bound to SERVER_PORT).
I am assuming this has something to do with my router's NAT table but I can't quite figure out the details.
My question is how can a packet be sent back from a different socket, other than the one that had been used for previous packets, and would I have had the same issue if the server was directly connected to the internet?
I wrote a small java program to demonstrate the issue:
Here is the server's code:
//create both sockets and a buffer
DatagramSocket serverSocket1 = new DatagramSocket(SERVER_PORT);
DatagramSocket serverSocket2 = new DatagramSocket();
byte[] buffer = new byte[512];
//receive a packet from serverSocket1
DatagramPacket packet1 = new DatagramPacket(buffer, buffer.length);
serverSocket1.receive(packet1);
System.out.println("received packet from: address = " + packet1.getAddress() + ", port = "+ packet1.getPort());
//send a packet from serverSocket2
DatagramPacket packet2 = new DatagramPacket(buffer, buffer.length, packet1.getAddress(), packet1.getPort());
serverSocket2.send(packet2);
System.out.println("sent packet back");
Here is the client's code: (note: SERVER_ADDRESS is set to my public ip)
//create a socket for the client and a buffer
DatagramSocket clientSocket = new DatagramSocket();
byte[] buffer = new byte[512];
//send packet1
DatagramPacket clientPacket1 = new DatagramPacket(buffer, 0, buffer.length, InetAddress.getByName(Server.SERVER_ADDRESS), Server.SERVER_PORT);
clientSocket.send(clientPacket1);
System.out.println("sent packet");
//receive packet2
DatagramPacket clientPacket2 = new DatagramPacket(buffer, buffer.length);
clientSocket.receive(clientPacket2);
System.out.println("received packet from: address = " + clientPacket2.getAddress() + ", port = "+ clientPacket2.getPort());
After running first the server and the the client I get the following output:
server:
received packet from: address = /107.107.56.147, port = 29098
sent packet back
client:
sent packet
My app is unable to receive the UDP packets when running in the emulator. UDP packets are sent by below java program on "localhost" over the port 49999.
DatagramSocket clientsocket;
DatagramPacket dp;
BufferedReader br;
InetAddress ia;
byte buf[] = new byte[1024];
int cport = 50000, sport = 49999;
clientsocket = new DatagramSocket(cport);
dp = new DatagramPacket(buf, buf.length);
br = new BufferedReader(new InputStreamReader(System.in));
ia = InetAddress.getLocalHost();
while(true)
{
Random rand = new Random();
String str1 = rand.nextInt(100) + "";
buf = str1.getBytes();
System.out.println("Sending " + str1);
clientsocket.send(new DatagramPacket(buf,str1.length(), ia, sport));
try{
Thread.sleep(100);
} catch(Exception e){}
}
Another java UDP server program running on the same localhost receives the packets fine. This means that the packets are sent to localhost:49999 correctly.
To forward the packets from localhost to the emulator, I did telnet redirect as below:
telnet localhost 49999
redir add udp:49999:49999
The UDP receiver in the app looks like this:
byte[] data = new byte[1400];
DatagramPacket packet = new DatagramPacket(data, 1400);
DatagramSocket socket = new DatagramSocket(49999);
socket.setSoTimeout(200);
try{
socket.receive(packet); ---->> This throws a SocketTimeoutException
} catch(SocketTimeoutException e){}
My understanding was that the telnet redirect should take care of forwarding the packets from my development machine's localhost:49999 to emulator's localhost:49999 so that the data is available on the DatagramSocket(49999). However it keeps throwing the SocketTimeoutException all the time.
It would be a great help to know what is the missing piece of the puzzle here.
After connecting to the localhost you may want to check that the port was actually asigned as intended with the command netstat -na in the cmd. It also might be worth a try to use the IP 127.0.0.1 instead.
This is my udp_broadcast server code where iam listening on 0.0.0.0
try{
socket = new DatagramSocket (7777,InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
while(true)
{
System.out.println(getClass().getName()+"ready recieve broadcast packets!");
//recieve a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf,recvBuf.length);
socket.receive(packet);
System.out.println(getClass().getName() +"packet recieved from :" +packet.getAddress().getHostAddress());
System.out.println("data is "+new String(packet.getData()));
String message = new String(packet.getData()).trim();
if(message.equals("p2p_project_node"))
{
byte [] senddata = "I_found_you_did_YOU".getBytes();
DatagramPacket sendpacket= new DatagramPacket(senddata,senddata.length,packet.getAddress(),packet.getPort());
socket.send(sendpacket);
System.out.println("packet sent to "+sendpacket.getAddress().getHostAddress());
}
}
}
on client side iam broadcasting packet 255.255.255.255 so that i get a reply from server
eventually and i endup in getting server ip address
udp_client_side code
try {
c = new DatagramSocket();
c.setBroadcast(true);
byte [] sendData = "p2p_project_node".getBytes();
//this is broadcasting to 255.255.255.255a
try{
DatagramPacket sendPacket = new DatagramPacket(sendData,sendData.length,InetAddress.getByName("255.255.255.255"),7777);
c.send(sendPacket);
System.out.println("rewuest sent to 255.255.255.255");
}
catch(Exception e) {
System.out.println("exception 255.255" +e);
}
on the server side iam getting error saying that
Exception java.net.BindException "Address already in use :cannot bind"
where am i going wrong if someone could help me it would be great Thanks in advance
The address is already in use. You cannot bind your socket to that address. Some other process already has a UDP socket bound to that poet. Possibly a previous instance of your own program.
Don't broadcast to 255.255.255.255. It was deprecated twenty years ago. Use the subnet broadcast address, or better still use multicast.
You can bind your socket to that port, if this port is occupied by a previous instance of your own program. You need to use "reuse" parameter in all instances of your program. Call .setReuseAddress(true); before binding.
Is it possible to either use the same port over multiple socket.send() or specify a port when creating a DatagramSocket? If so how. I am attempting hole-punching and need to listen from the port that is used and I cannot change the port the client is sending from.
try {
DatagramSocket dSocket = new DatagramSocket();
InetAddress serverAddr = InetAddress.getByName(TARGETIP)
int msg_len = currentMsg.length();
byte[] message = currentMsg.getBytes();
DatagramPacket dPacket = new DatagramPacket(message,msg_len,serverAddr,3222);
dSocket.send(dPacket);
updateConversationHandler.post(new systemUIUpdate("UDP Packet from " + dSocket.getLocalPort()));
}
catch (Exception e){
e.getMessage();
e.printStackTrace();
}
Every time this is run via an eventhandler dSocket.getLocalPort() shows a different port.
Yes you can. There are two solutions depending on what you want to do:
If you want to send the packet from a random port but same port everytime, don't close the socket as mentioned in previous answer.
If you even want to choose the port that you which to send from create DatagramSocket as:
DatagramSocket dSocket = new DatagramSocket(CLIENT_PORT);
Of course it does. You're creating a new socket every time, and never closing it, so the port stays in use, so the new socket gets a new port.
If you want the same port, use the same socket.
I am writing some client code using NIO to listen for UDP packets from multiple servers (many of which are configured to reply to the same port). I failed in my attempt to have dedicated channels to each known server NIO. 2 clients binding to same port, only 1 can read.
So I am now trying to bind to a port without specifying a destination
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(port));
My selector now successfully receives all UDP packets directed to this port from all my servers
...
SelectionKey selKey = it.next();
if (selKey.isValid() && selKey.isReadable()) {
DatagramChannel sChannel = (DatagramChannel) selKey.channel();
sChannel.getRemoteAddress();//My problem lies here
....
As expected sChannel.getRemoteAddress() returns null because I didnt configure it. So how do I determine where this packet originated?
The source address of a DatagramPacket is in the packet. See the Javadoc. Or, if you connect the DatagramChannel or its underlying DatagramSocket, you can get it from there ... but not otherwise.
To get remote address of a sender, you need to perform data receiving like this:
if (key.isReadable()) {
ByteBuffer byte_buffer = ByteBuffer.allocate(buffer_size);
InetSocketAddress remote_address = (InetSocketAddress) ((DatagramChannel)key.channel()).receive(byte_buffer);
byte_buffer.flip();
}
As you can see, receive method of the DatagramChannel class returns sender's address.
getRemoteAddress() will return null on DatagramChannel connection.
I used the following code :
//Declare the client address to be any random value, Just for initialization
InetSocketAddress clientAddress = new InetSocketAddress("127.0.0.1",1000);
//Declare the clientaddress' buffer
ByteBuffer buffer = ByteBuffer.allocate(255);
// Receive from the buffer
clientAddress = (InetSocketAddress)clientChannel.receive(buffer);
//This address is retained by masking receive
System.out.println("Client address : " + clientAddress);