Microsoft Docs

UDP Programming with Winsock

UDP (User Datagram Protocol) provides a connectionless, low‑overhead transport mechanism suitable for time‑critical applications such as streaming media, VoIP, and online gaming. The Winsock API offers a set of functions to create, configure, send, and receive UDP datagrams.

Key Concepts

  • Connectionless – no handshake, each datagram is independent.
  • Unreliable – delivery, ordering, and duplication are not guaranteed.
  • Message‑oriented – preserves packet boundaries.
  • Maximum payload size is limited by the underlying IP MTU (typically 1500 bytes).

Basic Steps

  1. Initialize Winsock
  2. Create UDP Socket
  3. Bind to Local Port
  4. Send Datagram
  5. Receive Datagram
  6. Cleanup
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
    printf("WSAStartup failed: %d\n", iResult);
    return 1;
}
SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udpSocket == INVALID_SOCKET) {
    printf("socket failed: %ld\n", WSAGetLastError());
    WSACleanup();
    return 1;
}
struct sockaddr_in localAddr;
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = INADDR_ANY; // listen on all interfaces
localAddr.sin_port = htons(5150);       // choose a port

if (bind(udpSocket, (SOCKADDR*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) {
    printf("bind failed: %ld\n", WSAGetLastError());
    closesocket(udpSocket);
    WSACleanup();
    return 1;
}
struct sockaddr_in destAddr;
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(5151);
InetPton(AF_INET, L"192.168.1.100", &destAddr.sin_addr);

const char* msg = "Hello, UDP!";
int sent = sendto(udpSocket, msg, (int)strlen(msg), 0,
                  (SOCKADDR*)&destAddr, sizeof(destAddr));
if (sent == SOCKET_ERROR) {
    printf("sendto failed: %ld\n", WSAGetLastError());
}
char buffer[1024];
int addrLen = sizeof(destAddr);
int recvLen = recvfrom(udpSocket, buffer, sizeof(buffer)-1, 0,
                       (SOCKADDR*)&destAddr, &addrLen);
if (recvLen == SOCKET_ERROR) {
    printf("recvfrom failed: %ld\n", WSAGetLastError());
} else {
    buffer[recvLen] = '\0';
    printf("Received: %s\n", buffer);
}
closesocket(udpSocket);
WSACleanup();

Full Example

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

int main()
{
    WSADATA wsa;
    if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
        printf("WSAStartup failed\\n");
        return 1;
    }

    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s == INVALID_SOCKET) {
        printf("socket failed\\n");
        WSACleanup();
        return 1;
    }

    struct sockaddr_in local = {0};
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = INADDR_ANY;
    local.sin_port = htons(5150);
    if (bind(s, (SOCKADDR*)&local, sizeof(local)) == SOCKET_ERROR) {
        printf("bind failed\\n");
        closesocket(s);
        WSACleanup();
        return 1;
    }

    struct sockaddr_in remote = {0};
    remote.sin_family = AF_INET;
    remote.sin_port = htons(5151);
    InetPton(AF_INET, L"127.0.0.1", &remote.sin_addr);

    const char* txt = "UDP test message";
    sendto(s, txt, (int)strlen(txt), 0, (SOCKADDR*)&remote, sizeof(remote));

    char recvbuf[512];
    int remoteLen = sizeof(remote);
    int rc = recvfrom(s, recvbuf, sizeof(recvbuf)-1, 0, (SOCKADDR*)&remote, &remoteLen);
    if (rc >= 0) {
        recvbuf[rc] = '\\0';
        printf("Received: %s\\n", recvbuf);
    }

    closesocket(s);
    WSACleanup();
    return 0;
}

Best Practices

  • Use non‑blocking sockets or I/O completion ports for high‑throughput servers.
  • Validate the size of incoming datagrams before processing.
  • Implement your own sequence numbers if ordering is required.
  • Consider setting SO_REUSEADDR when binding to well‑known ports.
  • Handle WSAEMSGSIZE to detect oversized packets.

Related Topics