cpp

networking

01_networking.cpp⚙️
// Module 10: Expert Topics
// Lesson: Systems Networking Essentials
// Build (Linux/macOS): g++ -std=c++17 01_networking.cpp -o networking_demo
// Note: The demo uses POSIX sockets. On Windows, compile with Winsock adjustments or use ASIO.

#include <chrono>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
#include <thread>

#if defined(_WIN32)
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#endif

using namespace std;

constexpr uint16_t kPort = 45'123;
constexpr const char *kMessage = "Hello over TCP";

void printPart(const string &title)
{
    cout << "\n========== " << title << " ==========" << endl;
}

#ifndef _WIN32
// PART 1: Minimal TCP echo server that handles a single client.
void runServer()
{
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        perror("socket");
        return;
    }

    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addr.sin_port = htons(kPort);

    if (bind(server_fd, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) < 0)
    {
        perror("bind");
        close(server_fd);
        return;
    }

    if (listen(server_fd, 1) < 0)
    {
        perror("listen");
        close(server_fd);
        return;
    }

    cout << "Server listening on 127.0.0.1:" << kPort << endl;

    sockaddr_in client_addr{};
    socklen_t len = sizeof(client_addr);
    int client_fd = accept(server_fd, reinterpret_cast<sockaddr *>(&client_addr), &len);
    if (client_fd < 0)
    {
        perror("accept");
        close(server_fd);
        return;
    }

    char buffer[256] = {};
    ssize_t received = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
    if (received > 0)
    {
        cout << "Server received: " << buffer << endl;
        string reply = string("Echo: ") + buffer;
        send(client_fd, reply.c_str(), reply.size(), 0);
    }

    close(client_fd);
    close(server_fd);
}

// PART 2: Simple client that talks to the server.
void runClient()
{
    this_thread::sleep_for(chrono::milliseconds(200)); // give server time to listen

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        perror("socket");
        return;
    }

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(kPort);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    if (connect(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) < 0)
    {
        perror("connect");
        close(sock);
        return;
    }

    send(sock, kMessage, strlen(kMessage), 0);

    char buffer[256] = {};
    ssize_t received = recv(sock, buffer, sizeof(buffer) - 1, 0);
    if (received > 0)
    {
        cout << "Client received: " << buffer << endl;
    }

    close(sock);
}
#endif

// PART 3: Protocol design considerations.
void discussProtocols()
{
    printPart("PART 3: Designing Network Protocols");
    cout << "- Choose TCP for reliable ordered delivery; UDP for low-latency datagrams." << endl;
    cout << "- Define clear message boundaries (length-prefix, delimiter, or fixed-size)." << endl;
    cout << "- Consider serialization formats: JSON, Protocol Buffers, FlatBuffers." << endl;
    cout << "- Always validate input from the network and authenticate peers when needed." << endl;
}

// PART 4: High-level networking stacks.
void discussHighLevelAPIs()
{
    printPart("PART 4: High-Level Networking Options");
    cout << "asio (Boost or standalone) provides portable async I/O." << endl;
    cout << "gRPC builds on HTTP/2 with strong tooling for RPC services." << endl;
    cout << "REST over HTTP can be served with cpp-httplib, drogon, oatpp, or served via NGINX." << endl;
    cout << "WebSocket libraries enable realtime messaging (uWebSockets, beast)." << endl;
}

int main()
{
    printPart("PARTS 1 & 2: Loopback Echo Demo");
#if defined(_WIN32)
    cout << "This minimal demo requires POSIX sockets. Use Winsock or ASIO on Windows." << endl;
#else
    thread server(runServer);
    thread client(runClient);
    server.join();
    client.join();
#endif

    discussProtocols();
    discussHighLevelAPIs();

    cout << "\nExercises:\n"
         << "1. Extend the server to handle multiple clients concurrently using std::thread.\n"
         << "2. Implement a UDP ping/pong pair and measure round-trip time.\n"
         << "3. Prototype a JSON-based protocol with message framing.\n"
         << "4. Explore header-only ASIO to avoid platform-specific socket code.\n";
    return 0;
}
Networking - C++ Tutorial | DeepML