Java Datagram Sockets (UDP)
Send and receive UDP datagrams in Java with DatagramSocket and DatagramPacket.
Java Datagram Sockets (UDP)
Socket and ServerSocket speak TCP — a reliable, ordered, connection-based stream. DatagramSocket speaks UDP, the other transport: connectionless and packet-based. You do not "connect"; you fire independent datagrams at an address and hope they arrive. There is no handshake, no ordering, and no delivery guarantee — and in exchange, no connection overhead and very low latency.
When UDP is the right tool
UDP trades reliability for speed and simplicity. It fits when:
- Occasional loss is acceptable — live audio/video, game state, telemetry. A dropped frame is better than a delayed one.
- Messages are small and self-contained — DNS queries, NTP time sync.
- You broadcast/multicast to many receivers — TCP cannot.
If you need every byte, in order (file transfer, web pages, databases), use TCP. Many applications layer their own light reliability on top of UDP rather than pay TCP's full cost.
The two classes
UDP in Java uses a pair:
DatagramSocket— the endpoint yousendfrom andreceiveon. There is no separate "server socket"; the same class does both, because there is no connection to accept.DatagramPacket— one datagram: a byte buffer plus, for sending, the destination address and port; for receiving, it is filled in with the sender's address and port and the data length.
DatagramSocket socket = new DatagramSocket(9000); // bind to receive on 9000
byte[] data = "hello".getBytes(StandardCharsets.UTF_8);
DatagramPacket out = new DatagramPacket(data, data.length, address, port);
socket.send(out); // fire and forget
byte[] buf = new byte[1024];
DatagramPacket in = new DatagramPacket(buf, buf.length);
socket.receive(in); // blocks; fills buf + sender infoA critical detail: after receive(), read exactly in.getLength() bytes from the buffer — the buffer is fixed-size but the datagram may be shorter. Set setSoTimeout(ms) so a lost packet does not block receive() forever.
A worked example: a UDP request/reply over loopback
This program runs a receiver on a background thread that waits for one datagram and replies to its sender, while the main thread sends a datagram and reads the acknowledgement — a full UDP round trip on the loopback interface.
What to take from the run:
- There was no
connect()and noaccept(). Both ends are justDatagramSockets; the sender fired a packet at an address and port, and the receiver picked it up. UDP has no connection, so the same class handles both roles — the asymmetry of TCP's client/server sockets disappears. - A
DatagramPacketcarried both data and addressing. The receiver learned who sent the request fromrequest.getAddress()andrequest.getPort()and replied straight to that endpoint — there is no persistent channel, so every reply must be addressed explicitly. - The body was decoded with
new String(data, 0, getLength(), …), not the whole 1024-byte buffer. A datagram fills only part of a fixed buffer; readinggetLength()bytes is mandatory, or you append trailing garbage from the unused buffer space. setSoTimeout(2000)guarded thereceive(). Because UDP guarantees nothing, a lost reply would otherwise block forever; a timeout turns "packet never came" into a catchableSocketTimeoutExceptionyou can retry or report.- The exchange worked here because loopback is lossless and ordered, but the API made no such promise. Over a real network this datagram could vanish, arrive twice, or arrive after a later one — which is exactly why reliability-sensitive applications choose TCP or build their own acknowledgement scheme on top of UDP.
Practice
A monitoring agent receives UDP datagrams into a reused 'byte[2048]' buffer via 'socket.receive(packet)', then converts the whole buffer with 'new String(packet.getData(), StandardCharsets.UTF_8)'. Short messages come out with trailing garbage. What is the fix?