Skip to main content

Multiplexing & Demultiplexing

A single host runs many programs that all want the network at once - a browser with a dozen tabs, a mail client, a music stream. They share one network interface and one IP address, yet each conversation stays separate. The transport layer makes that work with multiplexing and demultiplexing.

  • Multiplexing (sending side): gather data from many sockets, tag each piece with enough header info to tell them apart, and hand the segments to the network layer.
  • Demultiplexing (receiving side): read that header info on each arriving segment and deliver it to the correct socket.

Ports and sockets

A port is a 16-bit number (0 - 65535) that names an endpoint on a host. A socket is the actual object your program reads and writes; the OS keys its socket table by the identifiers in each segment.

For UDP, demultiplexing uses only the destination port: two segments with the same destination port land in the same socket, regardless of who sent them.

For TCP it takes more, because one server port serves many clients at once.

The connection 4-tuple

A TCP connection is identified by four values together:

FieldMeaning
Source IPwho sent it
Source portthe sender's endpoint
Destination IPthis host
Destination portthe service, e.g. 80

The OS finds the socket whose 4-tuple matches all four fields. This is why two tabs from the same client machine to the same server port are still separate connections: their source ports differ, so the 4-tuples differ, so they map to different sockets.

segment just arrivedsocket it matchedno matching socket
Arriving segments
1.1.1.1:5000 -> 10.0.0.1:80
2.2.2.2:5000 -> 10.0.0.1:80
1.1.1.1:5001 -> 10.0.0.1:80
9.9.9.9:6000 -> 10.0.0.1:80
9.9.9.9:6000 -> 10.0.0.1:443
Host 10.0.0.1 sockets
LISTEN :80listening
1.1.1.1:5000connected
1.1.1.1:5001connected
2.2.2.2:5000connected
Step through arriving segments to watch the OS demultiplex each one.
step 0 / 5
info

A server starts with one listening socket bound to a port (say :80). When a client connects, the OS spins up a connected socket pinned to the full 4-tuple. New segments prefer a matching connected socket; only traffic with no connected match falls back to the listener (to start a new connection). A segment for a port nobody is listening on is dropped.

Worked example: how many connections can one client support?

A client talking to a single server on port 443 is limited by its own pool of source ports, since destination IP, destination port, and often source IP are fixed. Ports are 16-bit, and the ephemeral range is typically around 32768 - 60999 (about 28,000 ports) on Linux. That means one client machine can have roughly 28,000 simultaneous connections to that one server before it runs out of distinct 4-tuples - each extra connection needs its own source port because everything else in the tuple is identical.

This is exactly the constraint behind SNAT port exhaustion: put a NAT gateway or load balancer in front of many clients sharing one public IP, and that shared IP has the same ~28,000-port budget divided among all of them. A single busy service opening thousands of outbound connections through the same NAT device can exhaust the pool, and every new connection attempt from anyone behind that NAT starts failing.

Gotcha

"Connection refused" or intermittent timeouts under load are sometimes not the server's fault at all - they are source port exhaustion on a shared NAT or load balancer, because the 4-tuple has run out of distinct source ports to hand out. This is a well-known failure mode for services that open a short-lived outbound connection per request (e.g. calling a downstream API per web request) instead of pooling and reusing connections. The fix is connection reuse/pooling, not a bigger server.

Why it matters

Demultiplexing is the mechanism behind "one server, thousands of clients." The listening socket accepts; each accepted connection gets its own socket keyed by the 4-tuple, and segments flow to the right place with no confusion.