The TCP Loopback Lifecycle
Every server is the same six calls; the sandbox's loopback is where they are safe to practice.
The six calls
#define _POSIX_C_SOURCE 200809L
#include <sys/socket.h> /* POSIX */
#include <netinet/in.h> /* POSIX */
#include <arpa/inet.h> /* POSIX */
int lfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa = {0};
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.0.0.1 only */
sa.sin_port = 0; /* 0 = kernel assigns */
bind(lfd, (struct sockaddr *)&sa, sizeof sa);
listen(lfd, 16);
int cfd = accept(lfd, NULL, NULL); /* blocks until connect */
The client mirrors it: socket then connect to the same sockaddr_in. Reading and writing on cfd is recv/send — the same bytes cross the loopback interface without touching a network.
Port 0 is the sandbox superpower. Binding to port 0 makes the kernel hand you a free ephemeral port; getsockname reports which. No fixed port means no collisions between parallel test runs — every challenge here uses this pattern.
TCP is a byte stream, not a message bus
send(s, "hello", 5, 0) does not create a "hello message". TCP may deliver those 5 bytes glued to the next send's bytes (coalescing) or split them (fragmentation). The receiver's recv returns whatever is in the pipe — 1 byte, 5, or 50 from three different sends.
This single fact motivates every protocol ever built on TCP:
- Delimiter framing: newline-terminated lines (HTTP/1, SMTP) — scan for the byte.
- Length-prefix framing: a fixed-width count then exactly that many bytes (HTTP/2, most binary protocols) — read the count, then read the count's worth.
Half-close is a feature
shutdown(cfd, SHUT_WR) sends EOF in the client→server direction while keeping the server→client direction open. A recv returning 0 means the peer closed its write side — that is how a server learns "the request is complete" without closing the response path. Note the contrast: recv == 0 is orderly EOF; recv < 0 with errno == EAGAIN means "nothing yet" when the socket is non-blocking or timeout-armed.
Honesty labels
- ISO C: none of this.
<stdio.h>knows no sockets. - POSIX: everything above — the feature macro is not decoration; without it musl/glibc hide the declarations.
- Sandbox: loopback only (
--network noneverified). External hosts are unreachable by design; code that must reach them belongs to a real environment, not this course.