Free Ebook cover Web Servers 101: How HTTP, DNS, TLS, and Reverse Proxies Work

Web Servers 101: How HTTP, DNS, TLS, and Reverse Proxies Work

New course

13 pages

TCP Connections and Ports: Getting a Reliable Channel to the Server

Capítulo 4

Estimated reading time: 11 minutes

+ Exercise

What TCP Is Doing for a Web Server

When a browser (or any HTTP client) needs to talk to a web server, it needs a transport that can carry bytes between two endpoints. TCP (Transmission Control Protocol) is the most common transport used for HTTP/1.1 and HTTP/2. TCP’s job is not to understand HTTP; it simply provides a reliable, ordered stream of bytes between two programs running on two machines.

“Reliable” and “ordered” are the key properties that make TCP a good fit for web traffic:

  • Reliability: if packets are lost on the network, TCP detects that and retransmits.
  • In-order delivery: the application reads bytes in the same order they were written by the sender, even if packets arrived out of order.
  • Flow control: TCP prevents a fast sender from overwhelming a slow receiver by using a receive window.
  • Congestion control: TCP adapts its sending rate to network conditions to avoid causing excessive congestion.

From your application’s perspective (browser, reverse proxy, web server), TCP looks like a file-like stream: you write bytes, the other side reads bytes. Under the hood, TCP segments those bytes into packets, numbers them, acknowledges them, and retransmits when needed.

Ports: How the Right Program Receives the Traffic

An IP address identifies a machine (or more precisely, a network interface). A port identifies a specific application endpoint on that machine. The combination of IP address + port + protocol (TCP or UDP) defines where traffic should be delivered.

On a server, many programs can be listening for incoming connections at the same time. Ports make that possible:

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

  • TCP 80 is commonly used for HTTP.
  • TCP 443 is commonly used for HTTPS (HTTP over TLS over TCP).
  • TCP 22 is commonly used for SSH.

Ports are 16-bit numbers (0–65535). In practice:

  • Well-known ports (0–1023): traditionally reserved for common services. On many systems, binding to these ports requires elevated privileges.
  • Registered ports (1024–49151): used by many applications and services.
  • Ephemeral ports (often 49152–65535, varies by OS): typically used by clients as temporary source ports when they initiate outbound connections.

A single TCP connection is uniquely identified by a 4-tuple: (source IP, source port, destination IP, destination port). This is why many clients can connect to the same server port simultaneously: each client uses a different source port (and often different source IPs), so each connection is distinct.

Listening vs. Connecting

On the server side, a process listens on a port. On the client side, a process connects to that IP:port. When the connection is established, the server accepts it and gets a new socket dedicated to that client connection.

Example: a reverse proxy might listen on 443, accept thousands of client connections, and then open separate outbound connections to upstream application servers on ports like 8080 or 3000.

How a TCP Connection Is Established (Three-Way Handshake)

Before any application bytes can flow, TCP establishes a connection using the three-way handshake. This handshake synchronizes sequence numbers and confirms that both sides can send and receive.

  • 1) SYN: client sends a packet with the SYN flag set, proposing an initial sequence number.
  • 2) SYN-ACK: server replies with SYN and ACK, acknowledging the client’s sequence number and providing its own initial sequence number.
  • 3) ACK: client sends an ACK acknowledging the server’s sequence number.

After this, the connection is established and data can be exchanged. This handshake adds at least one network round trip of latency before the first application bytes can be delivered. For HTTPS, a TLS handshake usually follows, adding additional round trips (the TLS details are covered elsewhere; here the key point is that TCP must exist first).

What Happens If the Server Port Is Closed

If nothing is listening on the destination port, the server’s OS typically responds with a TCP RST (reset), and the client sees “connection refused.” This is different from a timeout, which often indicates that packets are being dropped (for example by a firewall) or the server is unreachable.

Reliable Delivery: Sequence Numbers, ACKs, and Retransmissions

TCP breaks the byte stream into segments and assigns sequence numbers to bytes. The receiver sends acknowledgments (ACKs) indicating the next byte it expects. If the sender doesn’t receive an ACK within a certain time, it retransmits.

Important practical implications for web servers:

  • Packet loss increases latency: even if your server is fast, lost packets trigger retransmissions and delay the request/response.
  • Out-of-order arrival is handled: TCP reorders segments before delivering bytes to the application.
  • Duplicate packets are ignored: retransmissions can cause duplicates; TCP handles this.

From the HTTP layer, you might only notice this as “the request took longer,” not as a visible error. This is why network quality can dominate performance.

Flow Control and Congestion Control (Why Throughput Varies)

Two different mechanisms influence how fast data can be sent:

  • Flow control (receiver-driven): the receiver advertises a window size (receive window). If the receiving application is slow (or its buffers are full), the window shrinks, and the sender must slow down.
  • Congestion control (network-driven): the sender adjusts its congestion window based on perceived network congestion (loss, delay). Algorithms like CUBIC or BBR (depending on OS) determine how aggressively the sender increases throughput.

Practical example: serving a large file to a mobile client on a congested network. Even if your server can send at gigabits per second, TCP will pace itself based on the client’s receive window and the network’s congestion signals.

Connection Teardown: FIN, ACK, and TIME_WAIT

TCP connections are closed with a handshake as well, typically using FIN and ACK flags. Either side can initiate closure. A common pattern is:

  • One side sends FIN to indicate it will send no more data.
  • The other side sends ACK to acknowledge.
  • The other side later sends its own FIN when it’s done.
  • The first side sends a final ACK.

After closing, the endpoint that sends the final ACK often enters TIME_WAIT for a short period (commonly 1–4 minutes, OS-dependent). TIME_WAIT exists to ensure delayed packets from an old connection don’t get misinterpreted as part of a new connection with the same 4-tuple.

Why this matters operationally:

  • High connection churn (many short-lived connections) can create many sockets in TIME_WAIT, consuming ephemeral ports and kernel resources.
  • Keep-alive (reusing connections) reduces handshake overhead and reduces TIME_WAIT pressure.

Practical: Inspecting TCP Connections and Listening Ports

When troubleshooting “can’t reach the server,” you often want to answer two questions: (1) is the server listening on the expected port? (2) are connections being established?

Step-by-step: Check if a Server Is Listening on a Port

On Linux:

sudo ss -lntp

This shows listening (-l) TCP (-t) numeric (-n) ports and associated processes (-p). Look for entries like:

LISTEN 0 4096 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1234,fd=6))

Interpretation:

  • 0.0.0.0:443 means it’s listening on all IPv4 interfaces on port 443.
  • The process name and PID tell you which program owns the socket.

On macOS:

sudo lsof -nP -iTCP -sTCP:LISTEN

On Windows (PowerShell):

Get-NetTCPConnection -State Listen | Select-Object LocalAddress,LocalPort,OwningProcess

Then map process IDs to names:

Get-Process -Id <PID>

Step-by-step: Test Connectivity to a TCP Port

From a client machine, you can test whether a TCP handshake can be established.

Using netcat (nc):

nc -vz example.com 443

If it succeeds, you’ll see “succeeded” (meaning the TCP connection was established). If it fails quickly with “refused,” the port is reachable but not open. If it hangs and times out, something is dropping packets or routing is broken.

Using curl to see connection details:

curl -v http://example.com:80/

The -v output includes lines like “Connected to … port 80,” which confirms the TCP connection was made before HTTP was sent.

Step-by-step: Observe Established Connections

On a busy server, you may want to see how many connections are established and from where.

sudo ss -nt state established

You can count them:

sudo ss -nt state established | wc -l

And see which remote IPs are connecting most:

sudo ss -nt state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head

This is useful for diagnosing load spikes, abusive clients, or unexpected traffic patterns.

Practical: Understanding Ephemeral Ports and NAT

Clients usually don’t choose a fixed source port. The OS assigns an ephemeral port for each outbound connection. For example, your browser might connect from 192.0.2.10:53144 to 203.0.113.20:443. If you open many connections quickly, you can exhaust ephemeral ports, especially in environments with NAT (Network Address Translation) where many internal clients share one public IP.

Step-by-step: See the Ephemeral Port Range

Linux:

cat /proc/sys/net/ipv4/ip_local_port_range

macOS:

sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last

Windows:

netsh int ipv4 show dynamicport tcp

If you run a high-throughput client (load test tool, proxy, API gateway), ephemeral port exhaustion can show up as connection failures even when the server is healthy. Mitigations include reusing connections (keep-alive), increasing the ephemeral range, and tuning TIME_WAIT behavior carefully (OS-specific).

Why Web Servers Care About Backlogs and Accept Queues

When a server listens on a TCP port, the kernel manages queues for incoming connections. Two concepts are especially relevant:

  • SYN backlog: holds half-open connections during the handshake (after SYN received, before final ACK).
  • Accept queue: holds fully established connections waiting for the application to call accept().

If these queues fill up (for example, during a traffic spike or a SYN flood), clients may see timeouts or connection failures even though the server process is running. This is not an HTTP-level problem; it happens before HTTP is even sent.

In practice, reverse proxies and web servers expose settings like “backlog” or “worker connections” that influence how many concurrent connections can be handled. OS limits (file descriptors, socket buffers) also matter because each TCP connection consumes kernel resources.

Keep-Alive and Connection Reuse (Why It Matters for Performance)

Creating a new TCP connection costs at least one round trip for the handshake, plus additional overhead for slow start (TCP ramps up throughput gradually). If a client opens a new connection for every request, latency increases and server resources are wasted.

HTTP/1.1 introduced persistent connections (keep-alive) so multiple requests can reuse the same TCP connection. HTTP/2 goes further by multiplexing many concurrent streams over one TCP connection, reducing the need for many parallel connections.

Operationally, keep-alive affects:

  • Latency: fewer handshakes means faster subsequent requests.
  • Capacity: fewer total connections reduces CPU and memory overhead.
  • Load balancing: long-lived connections can “stick” to a particular backend longer, which can be good or bad depending on your architecture.

Common Failure Modes and What They Usually Mean

Connection refused

Typically indicates the destination host is reachable, but nothing is listening on that port (or a firewall actively rejects). Check that the service is bound to the correct interface and port, and that it’s running.

Connection timed out

Often indicates packets are being dropped (firewall rules, security groups, routing issues) or the host is down/unreachable. Timeouts can also happen if the server is overloaded and cannot complete handshakes quickly enough.

Reset by peer

Usually means the other side closed the connection abruptly (sent RST). This can happen if an intermediate device (proxy, firewall) terminates connections, if the server crashes, or if the application closes a socket while data is in flight.

Slow responses despite low server CPU

Can be caused by packet loss, congestion, small receive windows, or TCP slow start on new connections. Measuring network-level metrics (retransmits, RTT) can be as important as measuring application latency.

Practical: Mapping a Web Server Setup to TCP Ports

Consider a common deployment with a reverse proxy in front of an application server:

  • Reverse proxy listens on TCP 443 for clients.
  • Reverse proxy forwards to app on TCP 8080 (private network).
  • App talks to database on TCP 5432 (PostgreSQL) or TCP 3306 (MySQL).

Each hop is a separate TCP connection with its own behavior and limits. A slow database connection pool can indirectly cause the app to respond slowly, which can keep TCP connections open longer at the proxy, which can increase concurrent connection counts and memory usage. Thinking in terms of “how many TCP connections exist at each layer, and how long they live” is a practical way to reason about capacity.

Step-by-step: Verify Each Hop with Port Checks

  • Client → proxy: from outside, test nc -vz yourdomain 443.
  • Proxy listening: on proxy host, confirm ss -lntp shows 443 bound by the proxy process.
  • Proxy → app: from proxy host, test nc -vz app-internal 8080.
  • App listening: on app host, confirm ss -lntp shows 8080 bound by the app process.
  • App → DB: from app host, test nc -vz db-internal 5432 (or relevant port).

This isolates where the TCP path breaks before you spend time debugging HTTP configuration.

Now answer the exercise about the content:

A client runs nc -vz server.example 443 and the result is connection refused. What is the most likely meaning of this outcome?

You are right! Congratulations, now go to the next page

You missed! Try again.

Connection refused typically means the destination is reachable but no process is listening on that port, so the OS responds with a reset (RST). This differs from a timeout, which often indicates dropped packets or an unreachable host.

Next chapter

HTTP Messages: Methods, Status Codes, Headers, and Bodies

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.