CharacteristicUDPTCP
Connection setupNone (connectionless)3-way handshake
ReliabilityBest-effort (no retransmit)Guaranteed delivery
OrderingNot guaranteedIn-order delivery
Overhead8-byte header20–60 byte header
Broadcast / Multicast✅ Supported❌ Not supported
Use casesDNS, DHCP, VoIP, video, gamesHTTP, FTP, SMTP, databases

A UDP "server" receives datagrams on a fixed port; a UDP "client" sends datagrams and optionally waits for a reply.

// UDP Server — receives a datagram and echoes it back import java.net.*; public class UdpEchoServer { public static void main(String[] args) throws Exception { try (DatagramSocket socket = new DatagramSocket(9999)) { System.out.println("UDP server listening on port 9999"); byte[] buf = new byte[1024]; while (true) { DatagramPacket request = new DatagramPacket(buf, buf.length); socket.receive(request); // blocks until datagram arrives String msg = new String(request.getData(), 0, request.getLength()); System.out.println("Received: " + msg); // echo back to sender byte[] response = ("ECHO: " + msg).getBytes(); DatagramPacket reply = new DatagramPacket( response, response.length, request.getAddress(), request.getPort()); socket.send(reply); } } } } // UDP Client — sends a message and waits for the echo import java.net.*; public class UdpEchoClient { public static void main(String[] args) throws Exception { try (DatagramSocket socket = new DatagramSocket()) { socket.setSoTimeout(3000); // 3 s receive timeout InetAddress server = InetAddress.getByName("localhost"); byte[] data = "Hello UDP!".getBytes(); // send DatagramPacket packet = new DatagramPacket(data, data.length, server, 9999); socket.send(packet); // receive echo byte[] buf = new byte[1024]; DatagramPacket reply = new DatagramPacket(buf, buf.length); socket.receive(reply); System.out.println(new String(reply.getData(), 0, reply.getLength())); } } }

Calling socket.connect(address, port) on a DatagramSocket restricts it to a single peer — datagrams from other addresses are silently discarded. It also lets the OS detect ICMP "port unreachable" errors as PortUnreachableException.

DatagramSocket socket = new DatagramSocket(); socket.connect(InetAddress.getByName("192.168.1.100"), 9999); // send without specifying address — uses connected peer byte[] data = "ping".getBytes(); socket.send(new DatagramPacket(data, data.length)); // receive — only accepts packets from connected peer byte[] buf = new byte[256]; DatagramPacket pkt = new DatagramPacket(buf, buf.length); socket.receive(pkt); socket.disconnect(); // back to unconnected mode

Broadcast sends a datagram to all hosts on the local subnet. The destination address is the subnet broadcast address (e.g. 255.255.255.255). setBroadcast(true) must be called on the sender.

// Broadcast sender try (DatagramSocket socket = new DatagramSocket()) { socket.setBroadcast(true); byte[] data = "DISCOVER".getBytes(); InetAddress broadcast = InetAddress.getByName("255.255.255.255"); socket.send(new DatagramPacket(data, data.length, broadcast, 8888)); System.out.println("Broadcast sent"); } // Broadcast receiver (binds to the broadcast port) try (DatagramSocket socket = new DatagramSocket(8888)) { socket.setBroadcast(true); byte[] buf = new byte[256]; DatagramPacket pkt = new DatagramPacket(buf, buf.length); socket.receive(pkt); System.out.println("Discovered: " + pkt.getAddress()); } Broadcast is limited to the local subnet and is blocked by most routers. Use multicast for cross-subnet group delivery.

Multicast delivers datagrams to a group of subscribed hosts identified by a Class D IP address (224.0.0.0239.255.255.255). Use MulticastSocket — a subclass of DatagramSocket — to join and leave groups.

// Multicast receiver — joins a group on a specific network interface import java.net.*; public class MulticastReceiver { private static final String GROUP = "239.1.2.3"; private static final int PORT = 7777; public static void main(String[] args) throws Exception { InetAddress group = InetAddress.getByName(GROUP); NetworkInterface ni = NetworkInterface.getByName("eth0"); // use your interface try (MulticastSocket socket = new MulticastSocket(PORT)) { socket.joinGroup(new InetSocketAddress(group, PORT), ni); System.out.println("Joined multicast group " + GROUP); byte[] buf = new byte[1024]; for (int i = 0; i < 5; i++) { DatagramPacket pkt = new DatagramPacket(buf, buf.length); socket.receive(pkt); System.out.println("Got: " + new String(pkt.getData(), 0, pkt.getLength())); } socket.leaveGroup(new InetSocketAddress(group, PORT), ni); } } } // Multicast sender public class MulticastSender { public static void main(String[] args) throws Exception { try (DatagramSocket socket = new DatagramSocket()) { InetAddress group = InetAddress.getByName("239.1.2.3"); byte[] data = "Hello Multicast!".getBytes(); for (int i = 0; i < 5; i++) { socket.send(new DatagramPacket(data, data.length, group, 7777)); Thread.sleep(500); } } } } Multicast TTL (Time To Live) limits how many router hops a datagram traverses. Set it with socket.setTimeToLive(n). TTL=1 stays on the local subnet; TTL=32 crosses regional networks.

UDP datagrams are limited to 65,507 bytes (IPv4: 65,535 − 20 IP header − 8 UDP header). In practice keep payloads under 1,472 bytes to avoid IP fragmentation on a typical Ethernet MTU of 1,500 bytes.

ConcernSolution
Packet lossApplication-level ACK + retransmit (like QUIC / custom ARQ)
ReorderingSequence numbers in the payload; buffer and reorder on receiver
DuplicationTrack seen sequence numbers; discard duplicates
Large messagesFragmentation at application layer with reassembly buffer
// Simple sequenced packet — prepend a 4-byte sequence number ByteBuffer buf = ByteBuffer.allocate(4 + payload.length); buf.putInt(seqNum++); buf.put(payload); byte[] data = buf.array(); socket.send(new DatagramPacket(data, data.length, address, port)); // Receiver: extract sequence number DatagramPacket pkt = new DatagramPacket(new byte[1024], 1024); socket.receive(pkt); ByteBuffer received = ByteBuffer.wrap(pkt.getData(), 0, pkt.getLength()); int seq = received.getInt(); byte[] body = new byte[received.remaining()]; received.get(body);
PitfallFix
Buffer too small → truncated dataAlways allocate a buffer at least as large as the max expected datagram
Assuming delivery → silent data lossDesign for best-effort; add ACK if reliability matters
Multicast on wrong interfaceSpecify NetworkInterface explicitly in joinGroup
Firewall blocks multicast / broadcastOpen UDP ports; test on loopback first
Not calling setBroadcast(true)Broadcast sends silently fail or throw on some JVMs
Reusing DatagramPacket without resetting lengthReset pkt.setLength(buf.length) before each receive call