UDP Socket API

This document provides an in-depth look at the User Datagram Protocol (UDP) socket API in Windows. UDP is a connectionless protocol that offers speed and efficiency for applications where reliability is not paramount.

Introduction to UDP

UDP (User Datagram Protocol) is a transport layer protocol that provides a connectionless, unreliable datagram service. Unlike TCP, UDP does not establish a connection before sending data, nor does it guarantee delivery, order, or duplicate protection. This makes it ideal for real-time applications such as streaming media, online gaming, and DNS queries, where low latency is critical.

Key characteristics of UDP include:

  • Connectionless: No handshake is required to send data.
  • Unreliable: Packets may be lost, duplicated, or arrive out of order.
  • Datagram-Oriented: Data is sent in discrete packets (datagrams).
  • Low Overhead: Minimal header information, leading to faster transmission.

Core UDP Socket Functions

The Windows Sockets API (Winsock) provides functions to create, configure, send, and receive UDP datagrams. The fundamental socket type for UDP is SOCK_DGRAM.

Creating a UDP Socket

A UDP socket is created using the socket() function:

SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udpSocket == INVALID_SOCKET) {
    // Handle error
    WSAGetLastError();
}
  • AF_INET: Specifies the IPv4 address family.
  • SOCK_DGRAM: Indicates a datagram socket.
  • IPPROTO_UDP: Specifies the UDP protocol.

Binding a Socket

For a server application or a client that needs to receive data, the socket must be bound to a specific local IP address and port using bind():

struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345); // Example port
serverAddr.sin_addr.s_addr = INADDR_ANY; // Bind to any available interface

if (bind(udpSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
    // Handle error
    WSAGetLastError();
}

Using INADDR_ANY allows the application to receive datagrams destined for any IP address configured on the host.

Sending UDP Datagrams

Data is sent using sendto(), which requires specifying the destination address and port for each datagram:

struct sockaddr_in clientAddr;
clientAddr.sin_family = AF_INET;
clientAddr.sin_port = htons(6789); // Destination port
clientAddr.sin_addr.s_addr = inet_addr("192.168.1.100"); // Destination IP

const char* message = "Hello, UDP!";
int bytesSent = sendto(udpSocket, message, strlen(message), 0, (SOCKADDR*)&clientAddr, sizeof(clientAddr));

if (bytesSent == SOCKET_ERROR) {
    // Handle error
    WSAGetLastError();
}

sendto() returns the number of bytes sent or SOCKET_ERROR on failure.

Receiving UDP Datagrams

Datagrams are received using recvfrom(). This function fills a buffer with the received data and also provides the sender's address information:

char buffer[1024];
struct sockaddr_in senderAddr;
int addrLen = sizeof(senderAddr);

int bytesReceived = recvfrom(udpSocket, buffer, sizeof(buffer) - 1, 0, (SOCKADDR*)&senderAddr, &addrLen);

if (bytesReceived == SOCKET_ERROR) {
    // Handle error
    WSAGetLastError();
} else {
    buffer[bytesReceived] = '\0'; // Null-terminate the received data
    // Process received data in 'buffer' from sender with IP/port from senderAddr
}

recvfrom() blocks by default until a datagram is received or an error occurs.

Important Considerations

Datagram Size Limitations: UDP datagrams have a maximum size of 65,507 bytes (65,535 bytes for the total UDP packet minus 8 bytes for the UDP header and 20 bytes for the IP header). Applications should fragment data if it exceeds this limit.
Non-blocking Sockets: For applications requiring responsiveness, consider using non-blocking sockets. This is typically achieved by setting the socket to non-blocking mode using ioctlsocket() or by using WSAEventSelect() for event notification.
Error Handling: Always check the return values of Winsock functions and use WSAGetLastError() to retrieve specific error codes for robust error handling.

Common UDP Errors

Error Code Description
WSAECONNRESET A previous send operation failed because the remote host refused the datagram. This can happen if the destination port is not open.
WSAETIMEDOUT The connection timed out. For UDP, this typically implies a packet loss or that no response was received within a reasonable timeframe (if using a custom timeout mechanism).
WSAENETUNREACH The network is unreachable.

Example Use Cases

  • DNS (Domain Name System): UDP port 53 is used for quick name resolution queries.
  • DHCP (Dynamic Host Configuration Protocol): Used for IP address assignment.
  • VoIP and Streaming: Real-time audio and video transmission where occasional packet loss is acceptable.
  • Online Gaming: Fast-paced games often use UDP for game state updates to minimize latency.