From Tinygrams to ACK Clocks: RFC 896, Nagle, and Delayed Acknowledgments
Trace the 1984 Nagle algorithm from tiny-packet congestion to its documented interaction with delayed ACKs in the current TCP specification.
TCP can carry a one-byte application write in a packet whose headers are much larger than the data. In a 1984 discussion of this “small-packet problem,” John Nagle described how many tiny packets could amplify overhead and congestion. The resulting algorithm is now called Nagle’s algorithm. Its history is also a lesson in protocol interactions: a sender-side rule that coalesces short writes can wait on an acknowledgment, while a receiver may intentionally delay acknowledgments to reduce traffic.
The original RFC 896 is a historic discussion document, not a standards-track specification. The later host requirements in RFC 1122 describe the algorithm and delayed-ACK recommendations; the current TCP specification, RFC 9293, preserves the Nagle rule and explicitly notes the possible interaction with delayed acknowledgments. These documents describe protocol requirements, not the exact timers or implementation choices in every operating system.
The 1984 tinygram problem
RFC 896 opens with packet traces from early internetworks in which small TCP segments consumed a disproportionate share of network capacity. A one-character Telnet update could become a full packet, and many such packets could add header and processing cost without carrying much useful application data. Nagle rejected a fixed timer as a universal solution: one delay might be tolerable on a long-haul path but needlessly slow on a nearby Ethernet.
RFC 896’s 1984 rule is unconditional: if previously transmitted data remains unacknowledged, the sender inhibits new TCP segments when more user data arrives. The RFC explicitly says the rule needs no timer or test for the size of the newly received data. On an idle connection with no outstanding data, a small write can still be sent immediately; under RFC 896’s rule, later data is held until the outstanding data is acknowledged. The later RFC 1122 and RFC 9293 formulations also allow a full-sized segment to be sent before all outstanding data is acknowledged. A window update alone does not bypass Nagle; it matters only if the larger advertised window makes a full-sized segment sendable. Keep that later exception distinct from RFC 896’s original description.
Two algorithms on opposite endpoints
Nagle’s algorithm is a sender decision. Delayed ACK is a receiver decision. RFC 1122 says a TCP should implement delayed acknowledgments, but should not delay an ACK excessively: the delay must be less than 0.5 seconds, and a stream of full-sized segments should receive at least one ACK for every second segment. RFC 9293 says a TCP should implement Nagle’s algorithm to coalesce short segments and requires a way for an application to disable it on an individual connection.
The interaction can be illustrated without assuming one universal timer. An application writes a short request byte while the connection is idle; the sender emits it. Before its ACK arrives, the application writes another short piece. Nagle leaves that second piece queued because the first segment is still unacknowledged. If the peer accepts the first bytes but chooses to delay its ACK, the sender may remain unable to release the second write until the ACK or a full segment of data becomes available. For request/response protocols that wait for the queued bytes before replying, this can appear as a pause in the exchange.
That is a possible interaction, not a fixed “Nagle always adds 200 milliseconds” rule. ACK behavior depends on implementation, traffic pattern, and whether the receiver has a response or another reason to acknowledge sooner. RFC 9293 notes the issue and documents a Nagle modification used by some common stacks, while stating that the modification is not part of the TCP standard. It also says many applications disable Nagle through a socket option. The protocol documents do not promise identical latency across implementations.
Diagnose the exchange, not the label
When a small request feels slow, capture timestamps and sequence/acknowledgment numbers at both ends. Determine whether the sender has queued bytes awaiting an ACK, whether the receiver has sent the ACK, whether the advertised window changed, and whether the application itself is waiting before writing. A packet trace can distinguish a sender hold from loss, retransmission timeout, server processing time, or an application-level flush problem. The PSH flag does not bypass the rule: RFC 1122’s description says the sender buffers user data regardless of PSH while data is outstanding.
RFC 9293 requires an application-facing way to disable Nagle on an individual connection. Using that platform-specific control trades some coalescing for potentially more small segments. Measure the interactive request/response path before applying it, and keep bulk-transfer behavior separate. Often the cleanest fix is to frame and write a complete small request in one operation instead of issuing several tiny writes. If low-latency streaming is a requirement, make the socket policy explicit and test both latency and packet rate under realistic RTTs.
Historically, Nagle converted an observation about packet overhead into a simple feedback rule. Its continued presence in the TCP specification shows both the value and cost of local optimizations: the sender can reduce tinygram traffic without changing the wire protocol, but application latency emerges from the interaction of sender, receiver, and application timing.
Related:
- TCP Congestion Control: From the 1988 Collapse to CUBIC
- FreeBSD TCP Congestion Control: Selecting Algorithms and Measuring Real Paths
Sources: