Learn C++ - Networking Basics
Series/Learn C++/Episode 13
Episode 13 of 24

Learn C++ - Networking Basics

This episode covers networking basics in C++: TCP and UDP socket programming with BSD sockets, client-server communication and simple protocol design, byte order and address structures, error handling, as well as cross-platform considerations on Windows and Linux.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

Almost every modern system communicates over a network — HTTP, databases, message queues, even multiplayer games. In C++, network communication uses sockets: an interface managed by the operating system for sending and receiving data. The most basic sockets come from BSD sockets, the standard used on Linux and adopted by Windows through Winsock.

Episode 13 builds your networking foundation: the socket concept and the client-server model, simple TCP server and client, the importance of byte order, address structures, error handling, and the API differences between Windows and Linux.

The Socket Concept and the Client-Server Model

What Is a Socket

A socket is a communication endpoint identified by an IP address and a port. TCP provides a reliable, ordered connection, suitable for data that must not be lost. UDP is connectionless, fast, but can lose packets, suitable for streaming and games. The most common model is client-server: the server listens on a port, the client connects to that port.

The full workflow:

TCP socket flow
socket() -> bind() -> listen() -> accept() -> recv()/send()  [server]
socket() -> connect() -> send()/recv()                        [client]

The flow socket() -> bind() -> listen() -> accept() is the server socket's lifecycle, while a client only needs socket() -> connect() and then exchanges data. Both use the headers <sys/socket.h>, <netinet/in.h>, and <arpa/inet.h> on Linux.

A Simple TCP Server

Creating and Binding a Socket

The server creates a socket with socket(), binds it to a port with bind(), listens with listen(), then accepts connections with accept():

TCP server
cat > server.cpp <<'EOF'
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
 
int main() {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        std::cerr << "gagal membuat socket\n";
        return 1;
    }
 
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    addr.sin_addr.s_addr = INADDR_ANY;
 
    if (bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
        std::cerr << "gagal bind\n";
        return 1;
    }
    listen(fd, 5);
 
    sockaddr_in client{};
    socklen_t len = sizeof(client);
    int cfd = accept(fd, reinterpret_cast<sockaddr*>(&client), &len);
    std::cout << "Client terhubung\n";
 
    char buf[256];
    int n = recv(cfd, buf, sizeof(buf), 0);
    buf[n] = '\0';
    std::cout << "Terima: " << buf << "\n";
    send(cfd, "pong", 4, 0);
 
    close(cfd);
    close(fd);
}
EOF
g++ -std=c++20 server.cpp -o server

socket(AF_INET, SOCK_STREAM, 0) creates a TCP socket. htons(8080) converts the port to network byte order. bind(fd, ...) binds the socket to port 8080, listen(fd, 5) allows 5 connections in the queue, and accept() waits for an incoming connection. The <unistd.h> header provides close.

A Simple TCP Client

Connecting to the Server

The client creates a socket then connects to the server's address and port:

TCP client
cat > client.cpp <<'EOF'
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
 
int main() {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
 
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
 
    if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
        std::cerr << "koneksi gagal\n";
        return 1;
    }
    send(fd, "ping", 4, 0);
 
    char buf[256];
    int n = recv(fd, buf, sizeof(buf), 0);
    buf[n] = '\0';
    std::cout << "Server: " << buf << "\n";
 
    close(fd);
}
EOF
g++ -std=c++20 client.cpp -o client

inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) converts an address string to binary, and connect(fd, ...) connects to the server on port 8080. The address 127.0.0.1 is loopback — the server and client are on the same machine.

Testing with Netcat

Run the server, then test it with netcat without writing a client: the command nc 127.0.0.1 8080 uses netcat to test the server. Type text, press Enter, and the server receives it. Netcat is a network debugging tool you must master.

Byte Order and Address Structures

Big Endian versus Little Endian

Machines store numbers in different byte orders: little-endian (common on x86) stores the least significant byte first, big-endian (network order) the opposite. Networks use big-endian, so all values are converted when sent and received with htons and htonl (host to network) and ntohs and ntohl (the reverse). Without the htons(port) conversion, the port is read incorrectly on machines with a different byte order — a classic bug in inter-architecture communication.

Address Structures

sockaddr_in stores an IPv4 address with three important fields: sin_family (AF_INET), sin_port (the port in network order), and sin_addr (the binary IP address). For IPv6, use sockaddr_in6. Production applications usually wrap all of this in an abstraction so they don't touch per-OS details.

Error Handling and Cross-platform Concerns

Check Every Return Value

Every socket function returns a value that must be checked. errno explains the cause of the failure, and the pattern strerror(errno) turns it into a descriptive message like Address already in use. Common errors: the port is already used by another process, or binding without privileges to a port below 1024.

Windows Winsock

On Windows, sockets use Winsock: the <winsock2.h> header, a WSAStartup call before using sockets, closesocket instead of close, and linking the ws2_32 library. A cross-platform abstraction picks the header during preprocessing:

Cross-platform abstraction pattern
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <unistd.h>
#endif

The #ifdef _WIN32 block selects the header according to the platform during preprocessing. This is the conditional compilation pattern you'll learn more deeply in episode 20.

Tip

For production applications, consider a networking library like Boost.Asio or the standalone asio that unify Windows and Linux.

Conclusion

Here's what to take away:

  • A socket is a communication endpoint; TCP is reliable, UDP is fast.
  • Server: socket, bind, listen, accept. Client: socket, connect.
  • htons and htonl convert values to network byte order.
  • Check the return value of every socket function and read strerror(errno).
  • Windows uses Winsock with a slightly different API.
  • Netcat is a practical tool for testing servers.

In the next episode, episode 14, we'll discuss secure coding and safety — memory safety and buffer overflow mitigation, safe use of C string APIs versus std::string, input validation and sanitization with boundary checks, as well as cybersecurity best practices for C++ code.

Learn C++ - Networking Basics | Learn C++