Ch 16.4 UDP Socket Programming
UDP (User Datagram Protocol) socket programming transmits data as independent datagram packets without establishing a persistent connection. It is analogous to dropping a letter into a mailbox — you send it without waiting for confirmation that it arrived.
Because UDP does not verify delivery or order, it has lower reliability but significantly faster transmission and lower overhead than TCP.
1. UDP Core Structure
Unlike TCP, UDP has no concept of ServerSocket for accepting connections. Both sender and receiver use the same DatagramSocket class.
DatagramSocket: The socket for sending and receiving UDP packetsDatagramPacket: The container (envelope) holding the data, destination address, and port
Sender Receiver
| |
| DatagramSocket() | DatagramSocket(port)
| | receive() -- waiting...
| |
| DatagramPacket(data, addr, port) |
| send(packet) ==================> |
| | receive(packet) completed
| | extract data from packet
| |
| (no acknowledgment) |
2. Simple UDP Communication Example
Receiver (Server Role)
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpReceiver {
public static void main(String[] args) {
try {
// 1. Open socket on port 8888 and wait for incoming packets
DatagramSocket socket = new DatagramSocket(8888);
System.out.println("Waiting for UDP packets on port 8888...");
// 2. Prepare an empty packet buffer (assume max 512 bytes)
byte[] buffer = new byte[512];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 3. Block until a packet arrives; data is copied into the buffer
socket.receive(packet);
// 4. Convert received bytes to a string
String received = new String(buffer, 0, packet.getLength());
System.out.println("Message received: " + received);
System.out.println("From: " + packet.getAddress().getHostAddress()
+ ":" + packet.getPort());
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Sender (Client Role)
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpSender {
public static void main(String[] args) {
try {
// 1. Create a socket (OS assigns a random port for the sender)
DatagramSocket socket = new DatagramSocket();
// 2. Prepare data as a byte array
String message = "Hello! This is a UDP message.";
byte[] data = message.getBytes();
// 3. Resolve the recipient's address
InetAddress address = InetAddress.getByName("127.0.0.1");
// 4. Assemble the packet: [data, length, destination IP, destination port]
DatagramPacket packet = new DatagramPacket(data, data.length, address, 8888);
// 5. Send — no confirmation, no handshake
socket.send(packet);
System.out.println("Message sent.");
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. Two-Way UDP Communication
import java.net.*;
public class UdpEchoServer {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9090);
System.out.println("UDP echo server on port 9090...");
byte[] buffer = new byte[1024];
while (true) {
// Receive request
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
socket.receive(request);
String received = new String(request.getData(), 0, request.getLength());
System.out.println("Request: " + received);
if ("stop".equalsIgnoreCase(received.trim())) {
System.out.println("Stopping server.");
break;
}
// Echo back to the sender
String reply = "ECHO: " + received.toUpperCase();
byte[] replyBytes = reply.getBytes();
DatagramPacket response = new DatagramPacket(
replyBytes, replyBytes.length,
request.getAddress(), // reply to sender's address
request.getPort() // reply to sender's port
);
socket.send(response);
}
socket.close();
}
}
import java.net.*;
public class UdpEchoClient {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(5000); // 5 second receive timeout
InetAddress server = InetAddress.getByName("127.0.0.1");
int port = 9090;
String[] messages = {"Hello", "Java UDP", "stop"};
for (String msg : messages) {
// Send
byte[] sendData = msg.getBytes();
socket.send(new DatagramPacket(sendData, sendData.length, server, port));
System.out.println("Sent: " + msg);
if ("stop".equalsIgnoreCase(msg)) break;
// Receive echo
byte[] recvBuffer = new byte[1024];
DatagramPacket reply = new DatagramPacket(recvBuffer, recvBuffer.length);
socket.receive(reply);
System.out.println("Echo: " + new String(reply.getData(), 0, reply.getLength()));
}
socket.close();
}
}
4. UDP Broadcast
UDP supports broadcast— sending one packet that is received by all devices on the local network.
import java.net.*;
public class UdpBroadcastSender {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(true); // required for broadcast
String message = "Service announcement: server is at 192.168.1.100:8080";
byte[] data = message.getBytes();
// 255.255.255.255 = limited broadcast (local network)
InetAddress broadcastAddr = InetAddress.getByName("255.255.255.255");
DatagramPacket packet = new DatagramPacket(data, data.length, broadcastAddr, 9999);
socket.send(packet);
System.out.println("Broadcast sent: " + message);
socket.close();
}
}
import java.net.*;
public class UdpBroadcastReceiver {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9999);
System.out.println("Listening for broadcast on port 9999...");
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println("Broadcast received from " + packet.getAddress() + ": " + message);
socket.close();
}
}
5. TCP vs UDP — When to Use Which
| Feature | TCP | UDP |
|---|---|---|
| Connection | Required (3-way handshake) | None |
| Delivery guarantee | Yes (retransmit on loss) | No |
| Order guarantee | Yes | No |
| Speed | Slower | Faster |
| Overhead | Higher | Lower |
| Use cases | HTTP/HTTPS, file transfer, email | Live video, online games, DNS, IoT |
// Choose based on your use case:
// TCP — when data must arrive correctly and in order
// e.g., downloading a file, REST API calls, database queries
Socket tcpSocket = new Socket("server.com", 8080);
// UDP — when speed matters more than perfect delivery
// e.g., video frames (one dropped frame is OK), game position updates, DNS
DatagramSocket udpSocket = new DatagramSocket();
6. Practical Example: Simple Service Discovery
UDP broadcast is ideal for discovering services on a local network (like printers or IoT devices).
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
public class ServiceDiscovery {
static final int DISCOVERY_PORT = 12345;
static final String QUERY = "DISCOVER_SERVICES";
// Service provider: responds to discovery queries
static class ServiceProvider implements Runnable {
private final String serviceName;
private final int servicePort;
ServiceProvider(String name, int port) {
this.serviceName = name;
this.servicePort = port;
}
@Override
public void run() {
try (DatagramSocket socket = new DatagramSocket(DISCOVERY_PORT)) {
System.out.println("[Provider] " + serviceName + " listening for discovery...");
byte[] buffer = new byte[512];
while (true) {
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
socket.receive(request);
String query = new String(request.getData(), 0, request.getLength());
if (QUERY.equals(query.trim())) {
String response = serviceName + ":" + servicePort;
byte[] resp = response.getBytes();
socket.send(new DatagramPacket(resp, resp.length,
request.getAddress(), request.getPort()));
}
}
} catch (Exception e) {
System.err.println("[Provider] Error: " + e.getMessage());
}
}
}
// Service requester: broadcasts and collects responses
static List<String> discover(int timeoutMs) throws Exception {
List<String> found = new ArrayList<>();
try (DatagramSocket socket = new DatagramSocket()) {
socket.setBroadcast(true);
socket.setSoTimeout(timeoutMs);
byte[] query = QUERY.getBytes();
DatagramPacket probe = new DatagramPacket(query, query.length,
InetAddress.getByName("255.255.255.255"), DISCOVERY_PORT);
socket.send(probe);
byte[] buffer = new byte[512];
while (true) {
try {
DatagramPacket reply = new DatagramPacket(buffer, buffer.length);
socket.receive(reply);
found.add(new String(reply.getData(), 0, reply.getLength())
+ " @ " + reply.getAddress().getHostAddress());
} catch (SocketTimeoutException e) {
break; // collection window closed
}
}
}
return found;
}
}
Pro tip: UDP is ideal for applications where occasional packet loss is acceptable and low latency is critical:
- Video streaming: a missed frame appears as a brief glitch, not a fatal error
- Online multiplayer games: position updates come so frequently that one lost packet is corrected by the next
- DNS lookups: fast queries with built-in retry at the application layer
- IoT sensor data: high-frequency readings where an occasional missed reading is fine
For UDP in production, consider implementing your own lightweight reliability layer (sequence numbers, acknowledgments for critical packets) rather than using plain UDP for everything.