W3docs

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 you send from and receive on. 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 info

A 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.

java— editable, runs on the server

What to take from the run:

  • There was no connect() and no accept(). Both ends are just DatagramSockets; 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 DatagramPacket carried both data and addressing. The receiver learned who sent the request from request.getAddress() and request.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; reading getLength() bytes is mandatory, or you append trailing garbage from the unused buffer space.
  • setSoTimeout(2000) guarded the receive(). Because UDP guarantees nothing, a lost reply would otherwise block forever; a timeout turns "packet never came" into a catchable SocketTimeoutException you 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

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?