We've developed a Java application that sends several UDP datagrams to the very same destination IP address. Obviously the destination port is always the same one, but we can't seem to be able to set the source port to remain the same on each datagram.
If the data package we send is bigger than MTU the package is properly splitted over the same source port, but once we send a new data package the source port changes, generating a new firewall session (which network admin has warned us to be very bad due to the amount of sessions the application is generating).
Right now we're sending the packages with the following statement:
We've tried several approaches and the result is always the same, we can't seem to be able to set the source port to a fixed value.
Edit- pasting actual code:
private boolean sendImage(byte[] imageData, InetAddress address,
int port) throws UnknownHostException, SocketException {
boolean ret = false;
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(imageData, imageData.length, address, PUERTO_UDP);
socket.send(dp);
ret = true;
} catch (IOException e) {
Main.lanzarExcepcion(e);
ret = false;
} finally {
if (socket != null) {
socket.close();
}
}
return ret;
}
Thanks for your time!
I think your issue is that you are closing the actual DatagramSocket instead of reusing the same , and simply call socket.send(DatagramPacket). If you cant keep the client socket open , then you could even define the clients port like : DatagramSocket clientSocket = new DatagramSocket(9743); so each time you are calling a new clientSocket , it will get the same port or it will throw a java.net.BindException: Address already in use: Cannot bind
This will not solve the network sessions issue, because you are opening a new UDP Socket. Also i suspect that your network admin , sees the previous sessions , because you are not closing the UDP Sockets at all , but simply spawning them
As mentioned by #AntJavaDev
The solution was to:
1.- keep the DatagramSocket open
2.- pass src port in the arguments
3.- reusing the unclosed DatagramSocket for every new data packet to the same destination!
Thanks all!
The source port is an ephemeral port, generated for you by the underlying networking implementation. There is no reason to set it to a particular port number.
Related
I have a thread which periodically sends a datagram packet with the following setup:
DatagramSocket mySocket;
try {
mySocket = = new DatagramSocket(9999);
mySocket.connect(new InetSocketAddress(dstAddress, dstPort));
} catch (SocketException e) {
e.printStackTrace();
return;[![enter image description here][1]][1]
}
byte[] sentPacketBuffer = new byte[1];
DatagramPacket sentPacket = new DatagramPacket(sentPacketBuffer, sentPacketBuffer.length);
For each call of the send method:
mySocket.send(sentPacket);
I get a different source port on the receiver side.
I'v looked into this question, but the answer is actually related to setting the source port for the listener side.
Is there a way to make the source port (of the sender) persistent?
Edit
I used Android's VPNService to capture the received packets, and I dumped them to Wireshark:
As you can see only 1 packet has the correct source port.
Then I figured it might be related to the destination IP. The destination IP is not reachable from this device.
If I do make this address reachable (by connecting to 192.168.49.1, and having an interface in the same subnet) I get correct source port for all packets:
So, my question is now why does the destination reach-ability (or available interfaces) is related to the source port?
You are mistaken. The source port of datagrams sent by this code is always 9999.
NB Keep using the same socket. Creating and destroying a new one per datagram is pointless.
At this point, I am testing a webserver client/host system to be run on my raspberry pi (host) and on my pc (client). The basic idea is that every 5 seconds, the client on my pc sends a message to the host located at "192.168.0.11" at port 7051. It processes it and sends a message back to my pc.
For this I am using the following client code:
public static String getData() throws Exception {
try {
Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
socket.setReuseAddress(true);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int msg = 71;
out.write("TEALBEE_CUR:" + msg);
out.flush();
String input;
String data = "";
while ((input = in.readLine()) != null) {
data += input;
}
socket.close();
return data;
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
return null;
}
The problem here is that while data-flow is consistent and can run for at least a week; I lost use of other sockets connections on my pc, namely my Kodi remote control (this is media centre which I can control through a socket connection on my smartphone). My pc at address "192.168.0.37" accepts connections at port 193 for Kodi but after running the Java client for some time and sending a lot of requests to the server, I notice that the remote cannot connect anymore to my PC.
I thought that this might be the case because the sockets cannot be reused and after a single use the socket becomes unusable. This does seem to be the case as my host detects a different socket port for each request.
I tried to solve this by adding the code socket.setReuseAddress(true) and properly closing the socket after each message, but the problem still occurs.
How can I fix this properly (if possible only use one client socket and close this properly so it can be used again the next time).
EDIT: also important to note I can access 192.168.0.37:193 from my PC, but not from my smartphone when the socket connection cannot be established. Yes I am sure that the PC and smartphone and RPI are on the same network and without the client program running I CAN access 192.168.0.37:193 from my smartphone.
I'm building a program that will connect every computer in my LAN to my computer, through DatagramSocket's and DatagramPacket's (in other words, I'll be the server and the others will be clients). I made some research and read the documentation, and found out how it worked, and I've actually been able to send and recieve data across the network. I had two options for the data sending method in the client class, which I thought were equivalent, but it seems not.
The first one (Client1):
DatagramSocket socket = null;
DatagramPacket packet = null;
try
{
byte[] data= "test".getBytes();
packet = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.26"), 325);
socket = new DatagramSocket();
socket.send(packet);
}
catch (Exception ex)
{
...
}
And the second one (Client2):
DatagramSocket socket = null;
DatagramPacket packet = null;
try
{
byte[] data= "test".getBytes();
packet = new DatagramPacket(data, data.length);
socket = new DatagramSocket(325, InetAddress.getByName("192.168.0.26"));
socket.send(packet);
}
catch (Exception ex)
{
...
}
These two options came when I was making tests sending data to and from my own PC. My IP address is 192.168.0.26. With the first one I had no problems, but the second one throws two kinds of exceptions. I can verify that Client1 works running the next code in the computer at the same time
(Server)
byte data[] = null;
try
{
data= new byte[1000];
socket = new DatagramSocket(325);
packet = new DatagramPacket(datos, datos.length);
socket.receive(packet);
System.out.println(datos);
}
catch (Exception ex)
{
...
}
If I run Server first and then the Client1 option, it actually recieves the data. When I run the Client1 first and then the Server, obviously don't get any data but neither get any exceptions. The real problem (and actual question, sorry about so many, perhaps useless, info) is with Client2. If this is ran before Server, I get NullPointerException:
java.lang.NullPointerException: null address || null buffer
at java.net.DualStackPlainDatagramSocketImpl.send(DualStackPlainDatagramSocketImpl.java:115)
at java.net.DatagramSocket.send(DatagramSocket.java:676)
generated when method send() is invoked. I know maybe I should ignore this; even thought I'm a little bit newbie with Socket's, it seems wrong to send data if you know nobody will recieve it. In the other hand, when Server runs first and then Client2, I get BindException:
java.net.BindException: Address already in use: Cannot bind
at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.bind0(DualStackPlainDatagramSocketImpl.java:65)
at java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:95)
at java.net.DatagramSocket.bind(DatagramSocket.java:376)
at java.net.DatagramSocket.<init>(DatagramSocket.java:231)
at java.net.DatagramSocket.<init>(DatagramSocket.java:284)
from the line when the socket is initialized.
Due to that Client1 works, I'll use it; but I'd really like to know why does it work but Client2 doesn't. I read in another forum here about that BindException, and I understood it was caused when you attempt to use one port which is already in use, but in this sense Client1 should fail too. Could someone explain me the difference between Client1 and Client2?
You are binding to the same port, if you are running it on the same machine/address, you need to bind to different ports.
Like on the server:
socket = new DatagramSocket(325); //server binds its UDP/IP socket to port 325
On the client 2:
socket = new DatagramSocket(325, InetAddress.getByName("192.168.0.26"));
you are binding to the same port on the same machine/address that the "server" is using
On client 1:
packet = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.26"), 325);
//you are specifying the destination address and port the packet should be sent.
socket = new DatagramSocket();
//but in the DatagramSocket contructor you don't pass any address or port to bind to, so it will use an available port, not 325 as it is in use by the server.
As you said you are newly to network communication, be in mind that this is UDP/IP sockets, there's TCP/IP and others. UDP/IP is not connection oriented by specification, and does not guarantee the packet to be delivered.
Good Day,
I was taking a look at this tutorial to do a TCP Threadpool server.
http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
It works great for listening/RECEIVING to clients and processing, and returning a response. There is a class inside that I pass in WorkerRunnable into, and that basically prints out the remote socket address (who it was sent from)
public void run(){
synchronized(this){
this.runningThread = Thread.currentThread();
}
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
if(isStopped()) {
System.out.println("Server Stopped.") ;
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
this.threadPool.execute(
new WorkerRunnable(clientSocket,
"Thread Pooled Server"));
}
this.threadPool.shutdown();
System.out.println("Server Stopped.") ;
}
The problem is. The remote address is supposed to stay fixed (I am working within my own home wifi router). However, the IP address of the sender stays the same, but the port keeps changing!!
This is a big problem for me..as I need to be able to return a response to the user for future tasks and I actually save this address to use again to send data. When I ran this in a single TCP thread..it stayed fixed (the port).
Why does the threadpool cause the TCP remote address port to keep changing?
With TCP, the client socket port is most of the time (almost 99%, except for specific protocols) randomly chosen. But to you don't have to know it, the only thing you have to do is to keep the clientSocket reference to write back data to the client. If you want to send data to the other host after that the connection is closed, you have to start a ServerSocket on both sides with a fixed port.
Even if you test from same machine the client port will be random by default. I am not sure if there is any way to set the client source port. However, if you use netstat or capture the packet you can be sure the source port is different for every connection.
Background: I'm writing a simple UDP application to ping a beta server I manage every minute or so to tell me it is still up and running (I can't enable ping on the server for those that are wondering). I plan to run this on my phone to warn me when the server is no longer responding.
I'm trying to use the seemingly simple java.net.DatagramSocket as such:
try
{
socket = new DatagramSocket();
socket.bind(null);
}
catch (SocketException e)
{
System.out.println(e.toString());
throw e;
}
Let me also say that I have enabled the Internet permissions through the android manifest and if I remove the uses clause to do so, I get a permissions error so I'm sure that is working OK. When I download this code to an Android Virtual Device (AVD) and execute it, on the call to bind() I am presented with this exception:
03-17 19:07:39.401: INFO/System.out(338): java.net.BindException: Invalid argument
According to this documentation, the null argument is correct:
public void bind (SocketAddress localAddr)
Since: API Level 1
Binds this socket to the local address and port specified by localAddr. If this value is null any free port on a valid local address is used.
But not trusting documentation, I decided to enumerate the IP addresses on my device like this:
ArrayList<NetworkInterface> allInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
NetworkInterface eth = allInterfaces.get(0);
InetSocketAddress addr = new InetSocketAddress(eth.getInetAddresses().nextElement(), port);
try
{
socket = new DatagramSocket();
socket.bind(addr);
}
catch (SocketException e)
{
System.out.println(e.toString());
throw e;
}
When I step through the code, it works great and I can see the two IP address on the AVD but I get the exact same exception on the bind() call. Does anybody out there see what i might be missing? I will continue to research and hopefully post a solution to my own problem, but I am hoping somebody out there will be able to shortcut this for me.
[Edited: if you saw my previous response I made the classic debugging mistake of changing two variable in one test and it was the other one that solved my problem.]
I found the problem. It is the way I'm declaring the DatagramSocket that appears to cause problems. If I use a DatagramChannel to open the DatagramSocket in the following way then the bind() call is successful.
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
I've stumbled across this problem either and have found the cause: if you call the parameterless constructor new DatagramSocket(), this creates "a UDP datagram socket which is bound to any available port on the local host using a wildcard address" (as per the API docs). So this actually means, the Socket is already bound. My "fix" for this is as follows:
SocketAddress socketAddress = new SocketAddress(yourInetAddress, yourPort);
DatagramSocket serverSocket = new DatagramSocket(null);
serverSocket.bind(socketAddress);
This explicitly creates an unbound Socket (through the DatagramSocket (SocketAddress localAddr) constructor), making it possible to bind the Socket in turn.
This is probably the more elegant solution than creating an unnecessary channel.
P.S.: Strangely enough, this is where DatagramSocket differs from a TCP ServerSocket: the parameterless constructor of the latter will create an unbound ServerSocket, not triggering this problem.