Core Architecture · Topic 5 of 8

TCP/IP Stack & Sockets

200 XP

The Layer Model

The internet stack is typically described in four layers:

LayerProtocolWhat it does
ApplicationHTTP, gRPC, DNSYour actual data
TransportTCP, UDPEnd-to-end delivery, ports
InternetIPRouting across networks
LinkEthernet, Wi-FiPhysical hop delivery

Each layer wraps the one above in a header. A TCP segment becomes an IP packet becomes an Ethernet frame. On receipt, each layer strips its header and passes the payload up.

IP — Best-Effort Routing

IP (Internet Protocol) routes packets between machines. It provides no guarantees: packets can be dropped, reordered, or duplicated. Every IP packet carries source + destination address and a TTL that decrements at each router hop (preventing infinite loops).

IPv4 addresses are 32 bits (4.3B addresses — exhausted). IPv6 is 128 bits. NAT (Network Address Translation) lets millions of devices share one public IPv4 address by mapping private IP:port pairs.

TCP — Reliable Ordered Delivery

TCP adds reliability on top of IP:

  • Three-way handshake (SYN → SYN-ACK → ACK) establishes a connection and synchronizes sequence numbers.
  • Sequence numbers ensure in-order delivery even if packets arrive out-of-order.
  • Acknowledgements + retransmission: unacknowledged segments are resent after a timeout.
  • Flow control: the receiver advertises a window size — the max unacknowledged bytes the sender may have in-flight.
  • Congestion control (CUBIC, BBR): the sender probes available bandwidth and backs off on loss.
Client                Server
  |---SYN (seq=x)----->|
  |<--SYN-ACK(seq=y)---|
  |---ACK(seq=y+1)---->|
  |     Connected      |

TCP connection teardown uses a four-way FIN handshake. The TIME_WAIT state (2× MSL, typically 60–120s) prevents stale packets from old connections being misinterpreted by new ones on the same port.

Sockets

The socket API is the OS abstraction for network I/O:

int fd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
connect(fd, &server_addr, sizeof(server_addr));
write(fd, "GET / HTTP/1.1\r\n\r\n", 18);
read(fd, buf, sizeof(buf));
close(fd);

A socket file descriptor works like any other fd — you can read/write/select/poll/epoll on it. The kernel handles TCP segmentation, retransmission, and reassembly transparently.

epoll — Scalable I/O Multiplexing

select() and poll() scan all registered fds on each call — O(n). epoll (Linux) maintains a kernel-side interest list and returns only ready fds — O(1) for the common case. Node.js, Nginx, and virtually every high-performance server use epoll (or kqueue on macOS) under the hood.

TCP Performance Pitfalls

  • Nagle’s algorithm batches small writes to avoid network overhead. For latency-sensitive apps (game servers, trading), disable it with TCP_NODELAY.
  • Head-of-line blocking: a lost packet at the front of the stream blocks all subsequent data until it’s retransmitted. HTTP/2 multiplexing over TCP doesn’t eliminate this — it’s inherent to TCP’s ordered delivery guarantee. HTTP/3 solves this with QUIC (UDP-based).
  • Connection setup latency: 1.5 RTTs for the handshake + 1 RTT for TLS = significant for short-lived requests. HTTP Keep-Alive and connection pooling reuse connections.