Intro to Networking — Sockets and the Client-Server Model

By Carlos Montiel | Enterprise AI Specialist
Leer en español →
Published: 2026-07-28 | By: Carlos Montiel | Reading time: ~4 minutes

Before you can have a multiplayer game you need two programs that can talk to each other reliably. Today we learn the common language of every network: sockets.

What a Socket Is, in Simple Terms

In the previous lesson our enemies already "thought" locally, inside a single process. A multiplayer game breaks that assumption: now there are two (or more) programs running, possibly on different computers, that need to share the same world state. The fundamental piece that makes this possible is the socket: a connection endpoint that lets you send and receive data over a network, identified by an IP address and a port.

We'll work with Berkeley sockets (BSD sockets), the POSIX standard used natively by Linux and macOS. On Windows, the API is called WinSock and is nearly identical in usage — the main difference is initialization with `WSAStartup` and needing to link the `ws2_32` library.

// Headers for Linux/macOS (POSIX) #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> // Equivalent headers for Windows (WinSock2) // #include <winsock2.h> // #include <ws2tcpip.h> // #pragma comment(lib, "ws2_32.lib")

TCP vs UDP: the Most Important Decision

TCP guarantees ordered, reliable delivery of data, but has more latency. UDP is faster but doesn't guarantee packets arrive, or in what order. For this lesson and the next we'll use TCP because it's simpler to reason about while you're learning the fundamentals; in a real-time action game with many players, the industry usually prefers UDP with its own reliability layer, but that's outside the scope of an introductory course.

Building a Server: Step by Step

A TCP server always follows the same sequence: create the socket, bind it to an address and port (`bind`), put it into listening mode (`listen`), and accept clients (`accept`).

#include <cstdio> #include <cstring> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> int main() { int server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket < 0) { perror("Error creating socket"); return 1; } // Allows immediately reusing the port if the server restarts int option = 1; setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); sockaddr_in address{}; address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; // accept connections on any interface address.sin_port = htons(7777); // port 7777 if (bind(server_socket, (sockaddr*)&address, sizeof(address)) < 0) { perror("Error in bind"); close(server_socket); return 1; } if (listen(server_socket, 5) < 0) { // 5 = backlog queue size perror("Error in listen"); close(server_socket); return 1; } printf("Server listening on port 7777...\n"); sockaddr_in client_address{}; socklen_t address_size = sizeof(client_address); int client_socket = accept(server_socket, (sockaddr*)&client_address, &address_size); if (client_socket < 0) { perror("Error in accept"); close(server_socket); return 1; } printf("Client connected!\n"); char buffer[1024] = {0}; ssize_t bytes_read = recv(client_socket, buffer, sizeof(buffer) - 1, 0); if (bytes_read > 0) { printf("Message from client: %s\n", buffer); } const char* response = "Hello from the server"; send(client_socket, response, strlen(response), 0); close(client_socket); close(server_socket); return 0; }

`htons` converts the port number to network byte order (big-endian), regardless of whether your computer uses little-endian or big-endian internally. This detail — which exists precisely because different CPU architectures represent numbers differently — is a great candidate for asking your AI assistant to explain with a byte diagram if it's not immediately clear.

Building a Client

The client is simpler: it creates the socket and connects directly to a known address and port with `connect`.

#include <cstdio> #include <cstring> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main() { int client_socket = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in server_address{}; server_address.sin_family = AF_INET; server_address.sin_port = htons(7777); inet_pton(AF_INET, "127.0.0.1", &server_address.sin_addr); if (connect(client_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) { perror("Error connecting"); return 1; } const char* message = "Hello from the client"; send(client_socket, message, strlen(message), 0); char buffer[1024] = {0}; ssize_t bytes_read = recv(client_socket, buffer, sizeof(buffer) - 1, 0); if (bytes_read > 0) { printf("Server response: %s\n", buffer); } close(client_socket); return 0; }

Compiling and Testing Both Programs

g++ server.cpp -o server g++ client.cpp -o client # In one terminal: ./server # In another terminal: ./client

You should see "Client connected!" and the exchanged message in both terminals. As small as this seems, it's the complete foundation of every multiplayer game: two independent programs, communicating over a network with a protocol you define.

A Critical Detail: TCP Doesn't Respect Your Message Boundaries

A very common beginner mistake is assuming a `recv()` call receives exactly what a `send()` sent on the other side. TCP is a continuous byte stream, not a system of discrete messages — it can split a large message across several `recv()` calls, or merge several small messages into one. For a real game protocol you need to define your own "framing" (for example, sending the message size in 4 bytes first, then the content). We'll solve this formally in the next lesson, where we no longer just exchange a greeting message but the continuous state of a real multiplayer game.

In the next lesson we take these exact sockets and build a working multiplayer game, syncing player positions between client and server in real time.

Carlos Montiel
Enterprise AI Solutions Architect
Specialist in LLMs, Agents, and Orchestration
guatemalia.com/en/#contact · info@guatemalia.com

Need to implement AI at your company?

Carlos Montiel is an enterprise AI solutions architect. He implements LLMs, Agents, RAG, and orchestrators for companies across Guatemala and Latin America. Reach out for a consultation.

Contact Carlos Montiel

info@guatemalia.com