Mobile Computing · Mobile Networking
Counting Round Trips Before the First Payload Byte
A cold request on a phone crosses radio setup, name resolution, a transport handshake, and a TLS handshake before any application data moves, and each layer can be shortened.
The first request an application makes after a period of quiet is not one request. It is a stack of exchanges, each of which must complete before the next can begin, and each of which is paid in round trips against a link whose round trip is not small. On a cellular link the round trip is commonly tens of milliseconds and can exceed a hundred under load; on a congested wireless network it is worse and more variable. Multiplying a modest per-round-trip cost by the number of serialised exchanges gives the cold-start latency, and reducing that count is the entire craft of mobile request design.
The serial chain
Consider a request to a name the device has not recently resolved, over a transport connection that does not exist, to a server whose certificate the device has not seen.
The radio must first be usable. If the device is idle, a random access exchange and a connection setup precede anything at the internet layer, as described in Radio resource control states and the tail timer after the last byte. This is not a round trip in the internet sense; it is a sequence of message exchanges with the base station, and it is the largest single item in the budget when the device has been quiet.
Then name resolution. If the answer is cached and unexpired, it costs nothing on the wire. If not, the device sends a query to its resolver and waits for a response: one round trip, or more if the resolver must itself walk the hierarchy, which the device does not see but which contributes to the wait. On a network with a broken or slow resolver this is where a request stalls for seconds.
Then the transport handshake. For TCP, a SYN, a SYN-ACK, and an ACK: one round trip of the device’s own, with the third message carrying no data in the common case. For QUIC, the transport handshake is fused with the cryptographic one, which is the point of the protocol.
Then the cryptographic handshake. TLS 1.3 in its full form is one round trip to the server’s finished message, with the client’s certificate verification happening locally and the client’s own authentication, if any, following the server’s flight. TLS 1.2 in its full form is two round trips. Either way, the server’s certificate and the negotiation of parameters happen before the application’s bytes can be encrypted and sent.
Then the request itself, one round trip to the first byte of response.
For a TCP connection with a fresh TLS 1.3 handshake and an uncached name, the count is roughly one round trip for DNS, one for TCP, one for TLS, and one for the request: four serialised round trips, plus radio setup. At fifty milliseconds per round trip that is two hundred milliseconds of pure waiting before the server has even seen the request, and the server’s own processing and the response’s travel time are on top.
What reuse removes
Every item in that chain except the request itself is a candidate for elimination, and the mechanisms differ in what they require.
Connection reuse removes the transport and cryptographic handshakes together. A connection that is already established can carry a new request after one round trip for the request and response. The cost of keeping it is a small amount of state on both ends and, on the network side, the risk that a middlebox has silently dropped the mapping. On a cellular network, where the device may be behind a translator that expires idle mappings on the order of minutes, a pool that holds connections for longer than the mapping’s lifetime will find them dead on first use, and the failure appears as a timeout rather than as a reset.
Session resumption removes part of the cryptographic handshake without keeping a connection. TLS 1.3 offers two forms. Resumption by session ticket sends a ticket from a previous connection and a fresh key share; if the server accepts, the handshake completes in one round trip with no certificate exchange. Resumption by pre-shared key can be abbreviated further, at the cost of forward secrecy for the resumed session unless the implementation combines it with a fresh key exchange. Both forms require the client to have stored the ticket, and both are invalidated when the server rotates its keys, which happens on a schedule the client cannot see.
Name caching removes the resolution round trip, but only within the answer’s time to live. Applications that cache beyond the time to live trade a stale address for a saved round trip, and the trade fails when the server’s address changes, which is a common occurrence with load balancers and content networks.
Early data, in TLS 1.3, allows the client to send application data in the same flight as its handshake message, removing the request round trip for a resumed session. It is usable only when the server can tolerate a replay of that data, because an attacker can capture and resend it. A request that changes server state cannot use it; a request that fetches a document can.
Protocol choices and their round-trip shapes
The HTTP version determines how much of the connection’s capacity is available without additional handshakes.
HTTP/1.1 with one request per connection serialises everything: each new resource is a new handshake unless the client reuses the connection, and reuse is limited by the server’s response ordering, since a connection cannot interleave responses. Clients historically opened several parallel connections per host to work around this, which multiplies handshakes and, on a cellular link, multiplies the radio transitions that accompany them.
HTTP/2 multiplexes streams over one connection, so many resources share one handshake. Its cost is that all streams share one transport connection’s congestion window, so a single loss event delays every stream; and the connection is one failure domain, so a connection reset loses every stream at once. The protocol also makes header compression stateful across requests, which means a lost frame can desynchronise the compression context.
HTTP/3 moves the transport to QUIC over UDP. The handshake is one round trip for a new connection and zero for a resumed one, and streams are independent at the transport layer so a loss on one does not block another. The costs are that UDP is blocked or throttled on some networks, that middleboxes treat it differently from TCP, and that the transport’s own retransmission and pacing behaviour differs from TCP’s in ways that matter under loss.
The choice is not free in either direction, but the round-trip accounting is clear: for a cold start, QUIC with a stored ticket is one round trip to the request, while TCP with TLS 1.3 full handshake is three. Over a link with a hundred-millisecond round trip that difference is the difference between a responsive screen and a visible pause.
A budget written down
Expressing the budget explicitly is what makes a design reviewable. The following counts round trips for a first request under different assumptions; it ignores payload size and server processing.
| Stage | Cold, no reuse | Warm connection | Resumed TLS |
|---|---|---|---|
| Radio setup | ~2 message exchanges | none | none |
| Name resolution | 1 | none (cached) | none (cached) |
| Transport handshake | 1 | none | 1 (QUIC) or none |
| Cryptographic handshake | 1–2 | none | 0–1 |
| Request to first byte | 1 | 1 | 1 |
The table’s value is not the exact numbers, which vary with protocol version and network, but the structure: the warm path is one round trip, and everything above it is overhead that reuse eliminates. A design that opens a fresh connection per operation pays the overhead every time; a design that holds a connection pays it once and then must defend the connection’s lifetime.
Defending it has its own costs. A connection held open across a radio idle period may be released by the network, and the next use discovers that only when it sends. Platforms provide keepalive mechanisms at several layers, among them TCP keepalive probes, HTTP/2 ping frames, and QUIC’s own idle timeout negotiation, and each of them trades traffic for the ability to detect a dead connection before the application needs it. On a metered cellular link, a keepalive that fires every thirty seconds is a small packet and a large number of radio transitions, which is exactly the pattern Radio tail energy and the cost of the second request argues against.
The asymmetry that shapes the design
The costs in this budget are not symmetric between the client and the server, and that asymmetry explains most deployed choices.
For the server, a connection is memory and a file descriptor, and a handshake is CPU. Servers therefore prefer fewer, longer connections and pay for large machines. For the client, a connection is a small amount of state and a handshake is latency the user perceives. Clients therefore prefer to reuse aggressively and to open parallel connections when reuse is blocked, which is the opposite of what the server wants.
The reconciliation is at the protocol layer: multiplexing gives the client the latency benefit of parallelism while giving the server the resource benefit of a single connection. Where multiplexing is unavailable or broken, the two interests conflict directly, and the resolution is usually a compromise: a small pool of connections per host, sized to the point where additional parallelism no longer reduces the critical path.
There is one more asymmetry worth naming. The client’s round trip is not a constant; it depends on the radio state, the cell’s load, and the device’s position. A design that assumes a fifty-millisecond round trip will look adequate in one place and fail in another, and the failure is not a bug in the design’s logic but in its model. Counting round trips is useful precisely because the count is under the designer’s control while the round trip is not.