Networking

Understanding TCP Connections

Follow a TCP connection from its handshake to its final acknowledgment, and learn what throughput measurements can actually tell you.

A connection is a conversation between endpoints

TCP gives applications an ordered stream of bytes. Its useful promise is that the receiving application sees the stream in order, with missing data repaired while the connection remains viable. It does not preserve the boundaries of an application's writes. A program sending two short messages can therefore require explicit framing so that the receiver knows where one message ends and another begins.

A connection is identified by its local and remote addresses and ports. A web server can accept many connections on the same listening port because their remote endpoints differ. The protocol specification describes this connection model and its sequence-number machinery in RFC 9293.

The handshake creates shared state

The familiar SYN, SYN-ACK, and ACK exchange establishes the initial sequence numbers and confirms that both endpoints can communicate. A successful handshake demonstrates transport reachability at that moment; it does not prove that an HTTP application is healthy or that authentication will succeed.

Closing also involves state. Each direction can finish independently, and the protocol accounts for data still in flight. An application timeout, an explicit reset, and an orderly close describe different outcomes. Recording the actual error is more informative than putting every failure under the label “connection refused.”

In a hypothetical troubleshooting ticket, “the socket opened, then the response stalled” should lead to a different investigation from “no socket could be established.” That distinction narrows the next observation without prematurely blaming either the server or the network.

Two windows answer different questions

The receiving endpoint advertises how much data it can accept. The sender also maintains a congestion window, which limits how much unacknowledged data it injects into the path. One protects the receiver; the other responds to network conditions. The effective flight size depends on both limits.

The classic congestion-control framework includes slow start, congestion avoidance, fast retransmit, and recovery. These concepts are defined in RFC 5681, though an operating system can implement newer algorithms with different behavior. Seeing one algorithm's name is not a performance result. A shared upstream link, a busy receiver, and a distant path can each dominate a transfer regardless of the selected algorithm.

Latency changes the amount of data in flight

Consider an illustrative path that can sustain 100 megabits per second with a 200 millisecond round trip. Multiplying rate by time gives roughly 20 megabits, or 2.5 megabytes, in flight to keep that path busy. This is an explanatory calculation, not a measurement of any particular provider.

TCP window scaling allows the advertised receive window to represent values larger than the unscaled field permits. It is negotiated during connection establishment. TCP timestamps are another extension used for RTT measurement and protection against old sequence numbers; both are specified in RFC 7323.

The calculation also explains why a short test can be misleading: its startup phase may occupy a significant part of the observation. Always retain the duration and per-interval data alongside the final average.

A small socket example

This example connects to a local demonstration service. Run it only when you have a service listening on that address; it is not a discovery tool.

import socket

with socket.create_connection(("127.0.0.1", 9000), timeout=5) as connection:
    connection.sendall(b"hello\n")
    reply = connection.recv(4096)
    print(repr(reply))

Here sendall attempts to transmit the whole supplied buffer, while recv returns up to the requested amount. A single receive call is not a guarantee that a complete application message has arrived. Production code needs a framing rule, a size limit, and a policy for timeouts and early closure. The Python socket reference documents these APIs and their error behavior.

Measurements need a question

A single connection tests the behavior of one flow. Several parallel connections test an aggregate workload with separate congestion state. If four flows outperform one, that is useful evidence, but it does not mean one video request will receive their combined rate.

Write the intended question before running a benchmark: “Can one connection deliver this stream's bitrate with headroom?” is more actionable than “How fast is the server?” Keep direction, client location, test duration, and background traffic in the record. Include CPU utilization so that a saturated test process does not get mistaken for a congested route.

For a streaming workload, inspect sustained intervals and repeated tests at relevant hours. An average can conceal brief stalls, and a brief stall can be absorbed by a sufficiently large player buffer.

Diagnose before changing settings

Begin with a timeline: when did the connection open, when did bytes arrive, and when did progress stop? Compare one flow with a small parallel test, then compare directions. Preserve the raw results so that later configuration changes have a defensible baseline.

Retransmission counts deserve context. More retransmissions in a longer or faster transfer do not automatically imply a worse path. Record delivered bytes, duration, and observed delay as well. If an instrument cannot expose a counter, mark it unavailable rather than treating a blank field as zero.

A useful conclusion separates observation from inference: “the download stalled twice” is an observation; “the upstream transit link is congested” is a hypothesis that needs additional evidence.

Keep reading

Networking · 5 min read

Reading Traceroute Results

Learn what hop timings reveal, why missing replies can be harmless, and how to turn route output into careful network evidence.

Search notes

Press Escape to close.