Docs

README

Networking in C++

Table of Contents

  1. Network Programming Fundamentals
  2. Socket Basics
  3. TCP Client
  4. TCP Server
  5. UDP Communication
  6. Non-Blocking I/O
  7. Best Practices

Network Programming Fundamentals

The OSI and TCP/IP Models

┌──────────────────────────────────────────────────────────────────────────────┐
│                      NETWORK LAYERS OVERVIEW                                  │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   OSI Model              TCP/IP Model         What C++ Sockets Use           │
│   ─────────              ────────────         ────────────────────           │
│                                                                               │
│  ┌─────────────┐        ┌─────────────┐                                      │
│  │ Application │        │             │       ◄── Your C++ Application       │
│  ├─────────────┤        │ Application │           HTTP, FTP, Custom Protocol │
│  │ Presentation│        │             │                                      │
│  ├─────────────┤        └─────────────┘                                      │
│  │   Session   │                                                             │
│  ├─────────────┤        ┌─────────────┐       ◄── Socket API (TCP/UDP)       │
│  │  Transport  │        │  Transport  │           SOCK_STREAM, SOCK_DGRAM    │
│  ├─────────────┤        └─────────────┘                                      │
│  │   Network   │        ┌─────────────┐       ◄── IP Addresses               │
│  ├─────────────┤        │   Network   │           AF_INET, AF_INET6          │
│  │  Data Link  │        └─────────────┘                                      │
│  ├─────────────┤        ┌─────────────┐       ◄── Handled by OS              │
│  │  Physical   │        │Network Iface│                                      │
│  └─────────────┘        └─────────────┘                                      │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

TCP vs UDP Comparison

┌─────────────────────────────────────────────────────────────────────────────┐
│                         TCP vs UDP COMPARISON                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  TCP (Transmission Control Protocol)     UDP (User Datagram Protocol)       │
│  ────────────────────────────────────    ────────────────────────────       │
│                                                                              │
│   ┌───────────┐     Connection?     ┌───────────┐                           │
│   │  Client   │◄────────────────────│  Server   │                           │
│   └─────┬─────┘    Established!     └─────┬─────┘                           │
│         │                                 │                                  │
│         │──── Data packet 1 ─────────────►│                                  │
│         │◄─── ACK ────────────────────────│                                  │
│         │──── Data packet 2 ─────────────►│                                  │
│         │◄─── ACK ────────────────────────│                                  │
│                                                                              │
│   ✅ Reliable (guaranteed delivery)    ❌ No guarantee                      │
│   ✅ Ordered (packets arrive in order) ❌ May arrive out of order           │
│   ✅ Error checked                     ✅ Error checked                     │
│   ❌ Slower (overhead)                 ✅ Faster (minimal overhead)         │
│   ❌ Connection required               ✅ Connectionless                    │
│                                                                              │
│   Use for:                             Use for:                              │
│   • Web (HTTP/HTTPS)                   • Video streaming                     │
│   • Email (SMTP)                       • Online gaming                       │
│   • File transfer (FTP)                • DNS queries                         │
│   • Database connections               • VoIP                                │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Client-Server Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                     CLIENT-SERVER COMMUNICATION FLOW                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│        CLIENT                                        SERVER                  │
│   ┌─────────────────┐                          ┌─────────────────┐          │
│   │                 │                          │                 │          │
│   │  1. socket()    │                          │  1. socket()    │          │
│   │     Create      │                          │     Create      │          │
│   │                 │                          │                 │          │
│   └────────┬────────┘                          │  2. bind()      │          │
│            │                                   │     Assign port │          │
│            │                                   │                 │          │
│            │                                   │  3. listen()    │          │
│            │                                   │     Wait for    │          │
│            │                                   │     connections │          │
│            │                                   └────────┬────────┘          │
│            │                                            │                   │
│   ┌────────┴────────┐                          ┌────────┴────────┐          │
│   │  2. connect()   │ ─── TCP Handshake ────►  │  4. accept()    │          │
│   │     Connect to  │ ◄──────────────────────  │     Accept      │          │
│   │     server      │                          │     connection  │          │
│   └────────┬────────┘                          └────────┬────────┘          │
│            │                                            │                   │
│   ┌────────┴────────┐                          ┌────────┴────────┐          │
│   │  3. send()      │ ──── Request ─────────►  │  5. recv()      │          │
│   │     Send data   │                          │     Receive     │          │
│   └────────┬────────┘                          └────────┬────────┘          │
│            │                                            │                   │
│   ┌────────┴────────┐                          ┌────────┴────────┐          │
│   │  4. recv()      │ ◄─── Response ──────────  │  6. send()      │          │
│   │     Receive     │                          │     Send reply  │          │
│   └────────┬────────┘                          └────────┬────────┘          │
│            │                                            │                   │
│   ┌────────┴────────┐                          ┌────────┴────────┐          │
│   │  5. close()     │ ◄── Connection Close ──► │  7. close()     │          │
│   │     Close       │                          │     Close       │          │
│   └─────────────────┘                          └─────────────────┘          │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Socket Basics

A socket is an endpoint for communication - like a phone number for your program.

Required Headers (Linux/Unix)

#include <sys/socket.h>   // socket(), bind(), listen(), accept(), connect()
#include <netinet/in.h>   // sockaddr_in, INADDR_ANY
#include <arpa/inet.h>    // inet_pton(), inet_ntop(), htons()
#include <unistd.h>       // close()
#include <netdb.h>        // getaddrinfo(), gethostbyname()
#include <cstring>        // memset()

Socket Types

// AF = Address Family, SOCK = Socket type

// TCP Socket (Stream) - Reliable, ordered, connection-based
int tcpSocket = socket(AF_INET, SOCK_STREAM, 0);

// UDP Socket (Datagram) - Fast, connectionless, no guarantees
int udpSocket = socket(AF_INET, SOCK_DGRAM, 0);

// IPv6 variants
int ipv6TcpSocket = socket(AF_INET6, SOCK_STREAM, 0);
int ipv6UdpSocket = socket(AF_INET6, SOCK_DGRAM, 0);

Socket Creation Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│                        SOCKET CREATION PARAMETERS                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  socket(domain, type, protocol)                                              │
│          │       │      │                                                    │
│          │       │      └── Usually 0 (auto-select based on type)           │
│          │       │                                                           │
│          │       └── SOCK_STREAM ─── TCP (reliable, ordered)                │
│          │           SOCK_DGRAM ──── UDP (fast, no guarantees)              │
│          │           SOCK_RAW ────── Raw IP (advanced)                      │
│          │                                                                   │
│          └── AF_INET ─────── IPv4 (192.168.1.1)                             │
│              AF_INET6 ────── IPv6 (2001:db8::1)                             │
│              AF_UNIX ─────── Local (file-based IPC)                         │
│                                                                              │
│  Returns: Socket file descriptor (int) or -1 on error                       │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Address Structure

// IPv4 Address Structure
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));          // Zero out the structure
addr.sin_family = AF_INET;               // IPv4
addr.sin_port = htons(8080);             // Port (host to network byte order)
addr.sin_addr.s_addr = INADDR_ANY;       // Accept on any interface

// For specific IP address
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

// IPv6 Address Structure
sockaddr_in6 addr6;
memset(&addr6, 0, sizeof(addr6));
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(8080);
addr6.sin6_addr = in6addr_any;

Byte Order Functions

// Network byte order = Big Endian (most significant byte first)
// Host byte order = May be Big or Little Endian

htons(port);    // Host TO Network Short (16-bit, for ports)
htonl(addr);    // Host TO Network Long  (32-bit, for addresses)
ntohs(port);    // Network TO Host Short
ntohl(addr);    // Network TO Host Long
┌─────────────────────────────────────────────────────────────────────────────┐
│                           BYTE ORDER MATTERS!                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Port 8080 (0x1F90) in different byte orders:                               │
│                                                                              │
│  Little Endian (x86):     Big Endian (Network):                             │
│  ┌─────┬─────┐            ┌─────┬─────┐                                     │
│  │ 90  │ 1F  │     ──►    │ 1F  │ 90  │                                     │
│  └─────┴─────┘   htons()  └─────┴─────┘                                     │
│                                                                              │
│  ALWAYS use htons() for ports and htonl() for addresses!                    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

TCP Client

Connect to Server

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

int connectToServer(const char* host, int port) {
    // Create socket
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) return -1;

    // Server address
    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    inet_pton(AF_INET, host, &serverAddr.sin_addr);

    // Connect
    if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        close(sock);
        return -1;
    }

    return sock;
}

void sendMessage(int sock, const string& msg) {
    send(sock, msg.c_str(), msg.length(), 0);
}

string receiveMessage(int sock) {
    char buffer[1024];
    ssize_t bytes = recv(sock, buffer, sizeof(buffer) - 1, 0);
    if (bytes > 0) {
        buffer[bytes] = '\0';
        return string(buffer);
    }
    return "";
}

TCP Server

Basic Server

int createServer(int port) {
    // Create socket
    int serverSock = socket(AF_INET, SOCK_STREAM, 0);

    // Allow reuse
    int opt = 1;
    setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // Bind
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);
    bind(serverSock, (sockaddr*)&addr, sizeof(addr));

    // Listen
    listen(serverSock, 10);  // Backlog of 10

    return serverSock;
}

void acceptClients(int serverSock) {
    while (true) {
        sockaddr_in clientAddr;
        socklen_t clientLen = sizeof(clientAddr);

        // Accept (blocks)
        int clientSock = accept(serverSock,
                               (sockaddr*)&clientAddr,
                               &clientLen);

        if (clientSock >= 0) {
            // Handle client
            handleClient(clientSock);
            close(clientSock);
        }
    }
}

Multi-Threaded Server

void handleClient(int clientSock) {
    char buffer[1024];
    while (true) {
        ssize_t bytes = recv(clientSock, buffer, sizeof(buffer), 0);
        if (bytes <= 0) break;

        // Echo back
        send(clientSock, buffer, bytes, 0);
    }
}

void acceptClientsThreaded(int serverSock) {
    while (true) {
        sockaddr_in clientAddr;
        socklen_t clientLen = sizeof(clientAddr);
        int clientSock = accept(serverSock,
                               (sockaddr*)&clientAddr, &clientLen);

        if (clientSock >= 0) {
            thread t(handleClient, clientSock);
            t.detach();  // Run independently
        }
    }
}

UDP Communication

UDP Server

int createUDPServer(int port) {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);

    bind(sock, (sockaddr*)&addr, sizeof(addr));
    return sock;
}

void receiveUDP(int sock) {
    char buffer[1024];
    sockaddr_in clientAddr;
    socklen_t clientLen = sizeof(clientAddr);

    ssize_t bytes = recvfrom(sock, buffer, sizeof(buffer), 0,
                             (sockaddr*)&clientAddr, &clientLen);

    if (bytes > 0) {
        buffer[bytes] = '\0';
        cout << "Received: " << buffer << endl;

        // Reply
        sendto(sock, "ACK", 3, 0,
               (sockaddr*)&clientAddr, clientLen);
    }
}

UDP Client

void sendUDP(const char* host, int port, const string& msg) {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    inet_pton(AF_INET, host, &serverAddr.sin_addr);

    sendto(sock, msg.c_str(), msg.length(), 0,
           (sockaddr*)&serverAddr, sizeof(serverAddr));

    close(sock);
}

Non-Blocking I/O

select()

#include <sys/select.h>

void selectLoop(int serverSock, vector<int>& clients) {
    fd_set readSet;

    while (true) {
        FD_ZERO(&readSet);
        FD_SET(serverSock, &readSet);

        int maxFd = serverSock;
        for (int fd : clients) {
            FD_SET(fd, &readSet);
            maxFd = max(maxFd, fd);
        }

        timeval timeout = {1, 0};  // 1 second
        int ready = select(maxFd + 1, &readSet, nullptr, nullptr, &timeout);

        if (ready > 0) {
            // Check server socket
            if (FD_ISSET(serverSock, &readSet)) {
                int newClient = accept(serverSock, nullptr, nullptr);
                clients.push_back(newClient);
            }

            // Check client sockets
            for (int fd : clients) {
                if (FD_ISSET(fd, &readSet)) {
                    // Read from client
                }
            }
        }
    }
}

poll()

#include <poll.h>

void pollLoop(int serverSock) {
    vector<pollfd> fds;
    fds.push_back({serverSock, POLLIN, 0});

    while (true) {
        int ready = poll(fds.data(), fds.size(), 1000);  // 1s timeout

        if (ready > 0) {
            for (auto& pfd : fds) {
                if (pfd.revents & POLLIN) {
                    if (pfd.fd == serverSock) {
                        // Accept new connection
                    } else {
                        // Read from client
                    }
                }
            }
        }
    }
}

Best Practices

✅ Do

// 1. Check return values
if (connect(sock, addr, len) < 0) {
    perror("connect failed");
}

// 2. Set SO_REUSEADDR
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

// 3. Close sockets properly
close(sock);

// 4. Handle partial reads/writes
ssize_t sendAll(int sock, const char* data, size_t len) {
    size_t sent = 0;
    while (sent < len) {
        ssize_t n = send(sock, data + sent, len - sent, 0);
        if (n <= 0) return -1;
        sent += n;
    }
    return sent;
}

❌ Don't

// 1. Don't ignore byte order
addr.sin_port = 8080;  // WRONG
addr.sin_port = htons(8080);  // Correct

// 2. Don't assume recv fills buffer
char buffer[1024];
recv(sock, buffer, 1024, 0);
buffer[1023] = '\0';  // May not be null-terminated!

// 3. Don't forget to close
// Memory/resource leak if socket not closed

Quick Reference

// Create socket
socket(AF_INET, SOCK_STREAM, 0);  // TCP
socket(AF_INET, SOCK_DGRAM, 0);   // UDP

// Address setup
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
inet_pton(AF_INET, "ip", &addr.sin_addr);

// TCP Server
bind(sock, addr, sizeof(addr));
listen(sock, backlog);
accept(sock, clientAddr, &len);

// TCP Client
connect(sock, addr, sizeof(addr));

// Send/Receive
send(sock, data, len, 0);
recv(sock, buffer, buflen, 0);

// UDP
sendto(sock, data, len, 0, addr, addrlen);
recvfrom(sock, buf, len, 0, addr, &addrlen);

// Cleanup
close(sock);

Compile & Run

g++ -std=c++17 -Wall examples.cpp -o examples && ./examples
README - C++ Tutorial | DeepML