Skip to content
academia.sh

Lesson 14 / 18

Ports and Sockets

Addressing application endpoints, port number ranges, the four-tuple that makes a connection unique, and the distinction between a listening socket and a connection socket.

Contents

Throughout the previous topic, the term “port” was used without being defined: in the translation table’s key, in the leasing protocol’s numbers 67 and 68, in the destination server’s 443.

The place where the term is defined is the transport layer. The network layer delivers a packet to the correct machine and stops there; yet a single machine has dozens of programs using the network at the same time. This lesson’s question is how it is decided which program an incoming segment is handed to.

Multiplexing

A single machine has several network flows at once: a browser talks to several servers, a mail client runs in the background, a backup tool sends data. All of them share the same IP address.

The transport layer’s first job is to separate these flows. Two fields are placed in the header for the separation: source port and destination port. Each is 16 bits; the value range is between 00 and 6553565\,535.

Handing an incoming segment to the correct flow is called demultiplexing; loading outgoing segments onto a single network-layer flow is called multiplexing. This is the last link in the chain of multiplexing keys introduced in the Encapsulation and Headers lesson: the Ethernet type field leads to IP, the IP protocol field leads to TCP, the TCP port number leads to the application.

Number Ranges

Numbers are divided into three ranges:

Range Name Use
0–1023 Well-known Standardized services; assignment requires authorization
1024–49151 Registered Numbers registered to specific applications
49152–65535 Dynamic / ephemeral The range clients use as their source number

Numbers in the first range cannot be bound without elevated privilege on most operating systems. This restriction is a security measure: it prevents an unprivileged program from seizing a standard service’s number and impersonating it.

Some well-known numbers:

Number Protocol Service
22 TCP Secure shell
53 UDP and TCP Name resolution
67, 68 UDP Address leasing (server, client)
80 TCP Resource transfer
443 TCP and UDP Secure resource transfer

It should be noted that numbers are independent of protocol: TCP 443 and UDP 443 are separate endpoints. On the same machine, one can belong to one application and the other to a different one. There are two separate namespaces.

Numbers are a convention, not a requirement. A service can also run on a different number; in that case the client needs to know the number explicitly.

The Four-Tuple That Makes a Connection Unique

A port number alone is not enough to identify a flow. Thousands of clients connect to a server’s port 443 at the same time, and all of them use the same destination number.

What makes a TCP connection unique is the four-tuple:

(source address, source port, destination address, destination port)(\text{source address},\ \text{source port},\ \text{destination address},\ \text{destination port})

When the protocol is also counted, it becomes a five-tuple; the translation table’s key in the NAT and PAT lesson was this five-tuple.

Socket, at one end, is the address-and-port pair; at the operating-system level it is the object representing that endpoint. Two sockets form a connection.

The following program makes two connections to the same listening endpoint and prints the four-tuples from both sides.

import socket
import threading
import time


def server(ready: threading.Event, state: dict) -> None:
    listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listener.bind(("127.0.0.1", 9101))
    listener.listen(5)
    state["listener"] = listener.getsockname()
    ready.set()
    for _ in range(2):
        connection, peer = listener.accept()
        state.setdefault("connections", []).append((connection.getsockname(), peer))
        connection.close()
    listener.close()


ready = threading.Event()
state: dict = {}
threading.Thread(target=server, args=(ready, state), daemon=True).start()
ready.wait()
print("listening endpoint:", state["listener"])

for i in range(2):
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(("127.0.0.1", 9101))
    print(f"client {i + 1}: local={client.getsockname()} remote={client.getpeername()}")
    client.close()

time.sleep(0.2)
for local, peer in state["connections"]:
    print(f"server side: local={local} peer={peer}")

Output:

listening endpoint: ('127.0.0.1', 9101)
client 1: local=('127.0.0.1', 53044) remote=('127.0.0.1', 9101)
client 2: local=('127.0.0.1', 53045) remote=('127.0.0.1', 9101)
server side: local=('127.0.0.1', 9101) peer=('127.0.0.1', 53044)
server side: local=('127.0.0.1', 9101) peer=('127.0.0.1', 53045)

Ephemeral port numbers (53044, 53045) change on every run; the operating system picks them from the ephemeral range. What stays constant is that the two connections receive different numbers. The four-tuples:

Connection Source Destination
1 127.0.0.1:53044 127.0.0.1:9101
2 127.0.0.1:53045 127.0.0.1:9101

Three components are shared; only the source port differs — that is what provides the distinction.

Listening Socket and Connection Socket

One detail in the output stands out: on the server side, the number 9101 appears in both the listening socket and the two connection sockets. This is not a conflict, because the two socket types are looked up by separate keys.

Socket type Key Role
Listening socket (local address, local port) Accepts new connection requests
Connection socket The full four-tuple Carries data for an established connection

For an incoming segment, the operating system first looks for a full four-tuple match; if it does not find one and the segment is a new connection request, it routes the segment to the listening socket. This two-step lookup is what lets a single listening socket serve an unlimited number of connections.

The same distinction explains why a server’s concurrent capacity is not limited by the number of ports. The server’s number is fixed at a single value; what varies is the client side’s address and number.

On the client side, however, the limit is real: the number of concurrent connections a single client machine can establish to a single destination is limited by the count of numbers in the ephemeral range. This is the same capacity limit computed in the NAT and PAT lesson.

Endpoints in the Example Network

The flow the course follows is written as a four-tuple as follows:

Location Source Destination
At the client 192.168.10.196:49152 198.51.100.20:443
After translation 203.0.113.10:61001 198.51.100.20:443
As seen at the server 203.0.113.10:61001 198.51.100.20:443

The server never sees the client’s real address and number. The translation has changed two components of the four-tuple, and this change is invisible to both ends.

A flow that stays within the internal network, however, is not subject to translation. A request from the client in the administration section to the server room’s 192.168.10.226 address travels with the following four-tuple, unchanged along the way:

192.168.10.196:49160  ->  192.168.10.226:443

Binding Failures

An application’s attempt to bind to a number fails for two reasons.

Number in use. Another listening socket is already bound to the same address-and-number pair. This error is common when a server program restarts; the reason is that the previous connections have not finished their closing process. The detail of this behavior will be covered in the TCP lesson. The SO_REUSEADDR option in the program above exists precisely to get past this situation.

Insufficient privilege. An unprivileged process cannot bind to a number below 1024.

The address given when binding also matters. A socket bound to 127.0.0.1 is reachable only from the same machine; a socket bound to 0.0.0.0, which represents all interfaces, is also reachable from the network. A service running during local development being unreachable from the network is most often caused by this distinction.

Summary

  • The transport layer separates flows on the same machine using 16-bit port numbers.
  • Numbers are divided into three ranges: well-known (0–1023), registered (1024–49151), ephemeral (49152–65535).
  • TCP and UDP numbers are separate namespaces; the same number means two separate endpoints across the two protocols.
  • What makes a connection unique is the four-tuple: source address, source number, destination address, destination number.
  • A listening socket is looked up only by the local pair, a connection socket by the full four-tuple; this is why a single listening socket can serve unlimited connections.
  • The address given when binding a socket determines the scope of access: 127.0.0.1 is local only, 0.0.0.0 is all interfaces.

Next Step

The four-tuple names a flow; it says nothing about whether the flow will be reliable. The network layer can lose a packet, reorder it, or deliver the same packet twice. The next lesson covers the protocol that solves these three problems at once — its handshake, sequence numbers, retransmission, and flow control.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close