The UDP protocol is similar to the postal services.
A UDP socket allows to send and receive packets from/to any other reachable UDP socket.
There is no notion of connection!
If you send P1 and then P2 to the same adress. The target may receive P1 and then P2 or P2 and then P1 or only P1 or only P2 or nothing.
Java provides a very limited access to IP protocol:
Represented in Java by InetAddress with two sub-classes Inet4Address
and Inet6Address
.
We will always work with InetAddress
.
Created using the factory method
InetAddress.getByName(String host)
.
InetAddress addr1 = InetAddress.getByName("192.168.0.1"); InetAddress addr2 = InetAddress.getByName("FE80:0:0:0:0202:B3FF:FE1E:8329"); InetAddress addr3 = InetAddress.getByName("www.google.fr"); System.out.println(addr1+"\n"+addr2+"\n"+addr3);
/192.168.0.1 /fe80:0:0:0:202:b3ff:fe1e:8329 www.google.fr/64.233.166.94
This third example requires a DNS resolution.
InetAddress
= address (numerical) + [ name ]
Socket Address = IP Address + port number
Several constructors:
InetAddress inetAddress = InetAddress.getByName("www.google.com"); InetSocketAddress insa1 = new InetSocketAddress(inetAddress,7); InetSocketAddress insa2 = new InetSocketAddress("www.u-pem.fr",7); InetSocketAddress insa3 = new InetSocketAddress("192.168.0.1",1025); InetSocketAddress insa4 = new InetSocketAddress(7777); System.out.println(insa1+"\n"+insa2+"\n"+insa3+"\n"+insa4);
www.google.com/173.194.67.147:7 www.u-pem.fr/193.50.159.151:7 /192.168.0.1:1025 0.0.0.0/0.0.0.0:7777
UDP sockets are represented by the class DatagramChannel
.
They are created using the factory method:
DatagramChannel.open
DatagramChannel dc = DatagramChannel.open();
Not yet bound (no bind) = no socket address
Binding is done using datagramChannel.bind
.
dc.bind(null);
Binds to a random available port
To send a packet, we need data (ByteBuffer
in read-mode) and socket address of the recipient (InetSocketAddress
)
We use the method send
of DatagramChannel
:
datagramChannel.send(ByteBuffer buff, SocketAddress dest);
This method is blocking: it returns when buff.remaining()
data have been flushed to the system (to be sent).
DatagramChannel dc; ... ByteBuffer buff = StandardCharsets.UTF_8.encode("Hello world €"); InetSocketAddress dest= new InetSocketAddress("gaspard.univ-mlv.fr",7); dc.send(buff,dest);
To receive a packet, we need a ByteBuffer
ready to store incoming data (write-mode).
SocketAddress datagramChannel.receive(ByteBuffer buff);
This method is blocking: it returns when data of a packet has been read and stored into buff
.
The method will return the socket address of the sender.
DatagramChannel dc; ... ByteBuffer buff = ByteBuffer.allocate(1024); InetSocketAddress exp=(InetSocketAddress) dc.receive(buff); buff.flip(); System.out.println("Received "+ buff.remaining() + " bytes from "+ exp);
Don't forget the flip !
If the packet size is greater than the the buffer size, the extra data is lost without any notification.
The creation with open
and the binding with bind
reserve system resources
(descriptor, system buffers, port)
You must free these resources
either with datagramChannel.close();
or with try-with-resources
try(DatagramChannel dc = DatagramChannel.open()){ ... }