Reputation: 44745
UDP in Java thinks that UDP has "connections". This surprised me, coming from a C background where I had always used UDP as a fire-and-forget type of protocol.
When testing UDP in Java, I noticed that if the remote UDP port is not listening, I get an error in Java before I attempt to send anything.
What does Java do (without me asking it to) in order to be able to tell whether a remote UDP port is listening?
(The code below is run in the receiving thread for the socket. Sending is done in a different thread.)
try {
socket = new DatagramSocket(udpPort);
socket.connect(udpAddr, udpPort);
} catch (SocketException e) {
Log.d(TAG, "disconnected", e);
}
...
while (true) {
// TODO: don't create a new datagram for each iteration
DatagramPacket packet = new DatagramPacket(new byte[BUF_SIZE], BUF_SIZE);
try {
socket.receive(packet); // line 106
} catch (IOException e) {
Log.d(TAG, "couldn't recv", e);
}
...
produces the error below, if the remote socket is not listening.
java.net.PortUnreachableException:
at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:556)
at libcore.io.IoBridge.recvfrom(IoBridge.java:516)
at java.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:161)
at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:169)
at java.net.DatagramSocket.receive(DatagramSocket.java:253)
at com.example.mypkg.MyClass.run(MyClass.java:106)
at java.lang.Thread.run(Thread.java:856)
Caused by: libcore.io.ErrnoException: recvfrom failed: ECONNREFUSED (Connection refused)
at libcore.io.Posix.recvfromBytes(Native Method)
at libcore.io.Posix.recvfrom(Posix.java:131)
at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
...
Upvotes: 3
Views: 2641
Reputation: 718798
First of all, it is clear that this is not implemented using real Java. The "libcore.io" packages are not part of the Java SE libraries. These are Android stacktraces. (This doesn't change anything ... but it could.)
OK, so lets start with the exception. The javadoc for java.net.PortUnreachableException
says:
"Signals that an ICMP Port Unreachable message has been received on a connected datagram."
And for DatagramSocket.connect(...)
:
"If the remote destination to which the socket is connected does not exist, or is otherwise unreachable, and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a
PortUnreachableException
. Note, there is no guarantee that the exception will be thrown."
So here's what I think has happened. Prior to creating the incoming
socket, something on the client system has sent a UDP packet to the server on that port, and the server has responded with an ICMP Port Unreachable. Then your socket is created, and connected, and you call receive
. This does a recvfrom
syscall, and network stack responds with an ECONREFUSED error code ... which Java turns into a PortUnreachableException
,
So does this mean that UDP is connection oriented?
Not really, IMO. It is simply reporting the that it received an ICMP message in response to something that happened earlier.
What about the connect
methods, and the "connected socket" / "connected datagram" phraseology?
IMO, this is just some clumsy wording. The "connection" is really just referring to the fact that the datagram socket has been bound to a specific remote address and port ... so that you can send and receive datagrams without specifying the IP and port1.
These "connections" are pretty tenuous and certainly don't amount to making UDP "connection oriented".
What does Java do (without me asking it to) in order to be able to tell whether a remote UDP port is listening?
It is not doing anything. Java is simply reporting information from a previous ICMP message.
1 - Actually, there is a bit more to it than that. For example, binding tells the client-side OS to buffer UDP packets from that host / port an route UDP packets (and ICMP notifications) to the application. It also tells it not to respond with an ICMP Port Unreachable.
Upvotes: 4
Reputation: 310913
UDP in Java thinks that UDP has "connections".
No it doesn't, but UDP (regardless of Java) does have connected sockets. Not the same thing.
This surprised me, coming from a C background where I had always used UDP as a fire-and-forget type of protocol.
You can connect()
a UDP socket in C too. Look it up. What you describe has nothing to do with Java specifically.
When testing UDP in Java, I noticed that if the remote UDP port is not listening, I get an error in Java before I attempt to send anything.
That's because you connected the socket. One of the side-effects of that is that incoming ICMP messages can be routed back to the sending socket in the form of errors.
What does Java do (without me asking it to) in order to be able to tell whether a remote UDP port is listening?
It calls the BSD Sockets connect()
method.
Upvotes: 3
Reputation: 24730
The UDP server needs to listen on a local port.
Here's a code stub for a server.
int portNumber = 59123;
DatagramSocket server = new DatagramSocket(portNumber);
// read incoming packets
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while(true)
{
server.receive(packet);
byte[] data = packet.getData();
String text = new String(data, 0, packet.getLength());
echo(packet.getAddress().getHostAddress() + ":" + packet.getPort() + " received: '" + text + "'");
}
Upvotes: 0