Skip to main content
Tech Tutorials & Programming14 min readAug 17, 2026

How TCP Works Under the Hood: Congestion Control, CUBIC, BBR, and Modern TCP

Mahmoud Kassab
Mahmoud Kassab

Aug 17, 2026

Quick Answer

TCP evolved from a basic reliable transport protocol into a much more sophisticated system for managing bandwidth, latency, packet loss, and congestion. Improvements such as slow start, window scaling, SACK, packet pacing, ECN, RACK, CUBIC, and BBR allow modern TCP connections to use faster networks efficiently while adapting to changing network conditions.

Key Takeaways

  • TCP provides reliable, ordered data delivery by acknowledging received data and retransmitting anything that is lost.
  • Congestion control determines how much data TCP can safely keep in flight without overwhelming the network.
  • Technologies such as window scaling, SACK, RACK, and Tail Loss Probe helped TCP perform better on faster networks and recover from packet loss more efficiently.
  • CUBIC and BBR take different approaches to congestion control: CUBIC primarily reacts to network congestion signals, while BBR builds a model based on bandwidth, latency, and other path measurements.
  • Packet pacing and ECN can reduce sudden traffic bursts and give senders earlier information about network congestion.
  • With conventional HTTP CONNECT or SOCKS5 proxying, the client-to-proxy and proxy-to-target connections are separate TCP connections that can independently adapt to their own network conditions.
  • TCP has kept the same reliable byte-stream interface for applications while its underlying congestion control and loss-recovery mechanisms have continued to evolve.

TCP was designed for a network that looked very different from the internet we use today. Connections were slower, the network was smaller, and nobody was trying to fill a gigabit link from the other side of the world.

The basic protocol survived, but the machinery controlling it changed significantly. Modern TCP is the result of decades of improvements to sending speed, packet-loss recovery, queue management, and network fairness.

At its core, TCP opens a connection with a three-way handshake, numbers the bytes being sent, acknowledges what arrives, and retransmits anything that goes missing. This gives applications a reliable stream of data even though the IP network underneath may lose, duplicate, or reorder packets.

bash

That is the basic transport mechanism. The more interesting question is how TCP decides how much data to send.

TCP Has to Discover the Speed of the Network

A TCP sender does not know the capacity of every link between itself and the receiver. It cannot see how many other connections share those links or how much space remains in each router's queue.

It has to discover those conditions while the connection is running.

bash

TCP controls the amount of unacknowledged data in flight using two limits.

The receive window tells the sender how much data the destination can currently accept. It prevents a fast sender from overwhelming a slower receiver.

The congestion window represents how much data the sender believes the network path can carry safely. It prevents the sender from overwhelming the routers and links between the two endpoints.

The sender is effectively limited by whichever window is smaller.

As acknowledgments return, TCP releases more data, measures the round-trip time, watches for packet loss, and adjusts the congestion window.

bash

This feedback loop runs for the entire connection. Most of TCP's evolution has focused on making it faster, more accurate, and less disruptive to other traffic.

The Failure That Changed TCP

When Vint Cerf and Bob Kahn described the foundation of TCP in their 1974 internetworking paper, the network was much smaller. TCP was later separated from IP and standardized in RFC 793 in 1981.

Early TCP could prevent a sender from overrunning the receiver, but it did not have the network-wide control behavior used today.

That became a serious problem during the 1980s.

When routers became overloaded, they dropped packets. TCP senders saw the missing data and retransmitted it. Those retransmissions added more traffic to the same overloaded routers, which caused more packet loss and more retransmissions.

The network could enter congestion collapse. It would carry enormous amounts of traffic while delivering very little useful data.

The influential 1988 paper Congestion Avoidance and Control, by Van Jacobson and Michael Karels, documented and helped establish several techniques that reshaped TCP. Fast retransmit emerged in the same period and was described separately. Together, these developments included:

  • Slow start begins with a limited amount of data in flight and expands the congestion window as acknowledgments return.
  • Congestion avoidance makes that growth more cautious as the sender approaches the estimated capacity of the path.
  • Fast retransmit detects some missing data through repeated acknowledgments instead of waiting for a timer.
  • Adaptive retransmission timers follow changes in round-trip time.
  • Exponential backoff spaces out repeated retries when the network remains unhealthy.

Slow start is faster than its name suggests. The congestion window can grow roughly exponentially from one round trip to the next.

bash

The exact numbers depend on the implementation and network conditions. The important change was the behavior: TCP stopped treating the network as a pipe it could fill immediately and began testing the path in stages.

These mechanisms became the foundation of TCP congestion control, now documented in RFC 5681.

How TCP Kept Up With Faster Networks

Solving congestion collapse kept the network functioning, but faster links exposed new limitations. TCP needed larger windows, better loss recovery, and more control over when packets were transmitted.

Its evolution can be summarized as a series of practical upgrades:

bash

Larger Windows

The original TCP header used a 16-bit receive window field. Without extensions, the largest advertised window was 65,535 bytes.

That became a serious restriction as network speeds increased.

On a connection with a 100 millisecond round-trip time, a 65,535-byte window limits throughput to roughly 5.2 megabits per second. A much faster link would remain underused because the sender could not keep enough data in flight while waiting for acknowledgments.

Window scaling solved this by letting the endpoints negotiate a multiplier for the advertised window. TCP could then keep much more unacknowledged data in flight and use fast, long-distance paths effectively.

TCP timestamps were introduced alongside window scaling. They improve round-trip time measurements and help distinguish current packets from old duplicates. Both extensions are covered by RFC 7323.

The permitted initial congestion window also increased over time. Early implementations commonly began with one segment in flight. Experimental RFC 6928 permits an initial window of up to ten segments, although a sender may choose a smaller value.

This matters for short transfers. If a small response fits inside the initial window, TCP may deliver it without spending several round trips increasing its sending rate.

Faster Loss Recovery

Traditional TCP acknowledgments identify the first missing point in the byte stream. They do not provide a complete map of everything that arrived after the gap.

Consider five groups of data where the third one disappears:

bash

Selective Acknowledgment, or SACK, lets the receiver report that groups 4 and 5 arrived successfully. The sender can retransmit only the missing third group.

SACK was standardized in RFC 2018 in 1996. It greatly improved recovery when several packets disappeared from one window of data.

Modern TCP implementations can also use RACK and Tail Loss Probe.

RACK examines transmission and acknowledgment timing. If newer data has been acknowledged while an older packet remains unacknowledged, and an RTT-based allowance for packet reordering has elapsed, TCP can infer that the older packet was probably lost.

Tail Loss Probe helps when a packet disappears near the end of a transfer. There may not be enough later data to generate the repeated acknowledgments needed by fast retransmit, so the sender transmits a small probe instead of waiting for the full retransmission timeout.

The combined mechanism is specified in RFC 8985.

These improvements did not make packet loss disappear. They reduced the amount of time TCP spends discovering and repairing it.

Packet Pacing and Earlier Warnings

The congestion window controls how much data may be in flight. It does not necessarily control when each packet leaves.

Without pacing, a sender may release its entire allowance as one short burst. The average sending rate may be safe, but the burst can briefly overflow a router queue.

bash

Both lines contain the same number of packets. The second places less sudden pressure on the network.

A packet pacer turns the rate chosen by the congestion controller into a smoother transmission schedule. This can reduce queue spikes and lower the chance of several packets being dropped together.

Explicit Congestion Notification, or ECN, improves the feedback sent in the other direction.

Normally, a router signals congestion by dropping a packet. With ECN, a compatible router can mark the packet instead. The receiver reports that mark, allowing the sender to reduce its rate before the queue overflows.

ECN is defined in RFC 3168. The newer Accurate ECN specification gives senders more detailed information about how much congestion was encountered.

Together, these features improved the same control loop:

bash

CUBIC and BBR Use Different Strategies

A congestion control algorithm decides how TCP changes its sending rate as network conditions change.

CUBIC and BBR preserve the same TCP connection, acknowledgments, and reliable byte stream. They differ in how the sender estimates the safe amount of traffic.

How CUBIC Works

Older Reno-style congestion control increased the congestion window linearly during congestion avoidance.

That worked reasonably well on slower networks. On a fast connection with a large round-trip time, recovering after a loss could take too long. The connection might spend a significant amount of time below the available capacity.

CUBIC uses a cubic growth function instead.

After congestion occurs, CUBIC remembers the previous window size. It reduces the window, then begins growing again. Growth becomes more cautious as it approaches the previous limit because that is where congestion was last encountered. If the connection moves beyond that point without trouble, growth accelerates again.

bash

CUBIC learns mainly by increasing the amount of data in flight until the network provides a congestion signal through packet loss or ECN.

This approach is mature and widely deployed. CUBIC is the default congestion controller in major Linux, Windows, and Apple TCP stacks and is standardized in RFC 9438.

Its weakness appears when routers have large buffers. CUBIC may continue increasing its window while packets accumulate in a queue. Throughput remains high, but latency rises before packet loss finally signals that the sender should slow down.

This is one cause of bufferbloat.

How BBR Works

BBR stands for Bottleneck Bandwidth and Round-trip propagation time.

BBR began with a model centered on bottleneck bandwidth and minimum round-trip time. The current BBRv3 model also incorporates packet-loss rate. Its core measurements include:

  • The highest rate at which data is being delivered
  • The lowest round-trip time observed when queues are relatively empty
  • The packet-loss rate in BBRv3

Together, these measurements provide an estimate of how much data the path can carry while remaining fully utilized.

BBR uses packet pacing to send near that estimated rate. It periodically probes for additional bandwidth and checks whether the path's minimum round-trip time has changed.

bash

The original BBR research challenged the idea that packet loss always means congestion.

Wireless links can lose packets because of interference or weak signals. A loss-based algorithm may reduce its rate even when the path still has available capacity.

The reverse problem occurs with large router buffers. A queue can add substantial latency without dropping any packets. A sender waiting for loss may continue making that queue larger.

BBR tries to operate near the path's estimated capacity without requiring a full queue and packet loss to discover it.

CUBIC Compared With BBR

Main signal

CUBIC responds primarily to packet loss or ECN. BBR builds its model from delivery rate, round-trip time, and, in BBRv3, packet-loss rate.

How capacity is found

CUBIC increases its congestion window until the network pushes back. BBR builds a model of the path and paces traffic around that estimate.

Where they can perform well

CUBIC behaves predictably across a wide range of public internet paths. BBR can be effective on long-distance, wireless, lossy, or heavily buffered paths.

Main tradeoff

CUBIC can create larger queues while waiting for a congestion signal. BBR depends on the accuracy of its model and can behave differently depending on its version and the other traffic sharing the bottleneck.

Neither algorithm is universally faster.

bash

Modern CUBIC implementations can use pacing and ECN. BBRv3 explicitly considers packet loss and, when ECN is enabled, recognizes CE marks as congestion, although the current draft does not define a specific ECN response. The distinction is about their primary strategy, not the only signals they can understand.

Both algorithms can be changed at the sender without replacing HTTP, TCP, or the routers between the endpoints. That flexibility has allowed TCP performance to improve without requiring the internet to adopt a completely new transport protocol.

How Proxies Work With TCP

For a conventional TCP-based HTTP CONNECT or SOCKS5 CONNECT flow, the proxy acts as a transport endpoint between the client and target. The client establishes one TCP connection to the proxy, and the proxy establishes another connection to the target.

bash

This does not weaken TCP's reliability. Both connections still provide ordered delivery, retransmit missing data, and adjust their sending behavior as network conditions change. The useful difference is that each leg can be managed independently.

  • Each connection adapts to its own round-trip time, available capacity, and packet loss.
  • Missing packets are recovered on the specific leg where the loss occurred.
  • The proxy's TCP stack can use its own pacing, buffers, timers, and sending strategy.
  • Persistent connections and connection pooling can reduce repeated setup costs where the proxy architecture supports them.
  • Depending on its placement, upstream connectivity, and load, a proxy can sometimes provide a more stable or better-connected intermediate path.

This separation is especially useful when the two sides of the route have very different conditions. A mobile client may have a variable connection to the proxy while the proxy maintains a stable, high-capacity connection toward the target. Each side can react to its own conditions instead of sharing one set of transport assumptions across the full route.

An HTTP CONNECT tunnel follows the same model. TLS can remain end to end between the client and target while the encrypted bytes travel across two independently managed TCP connections.

The target generally sees the TCP/IP characteristics of the proxy's outbound connection. The resulting fingerprint can also reflect the proxy host's operating system and network stack, kernel configuration, middleboxes, and any TCP normalization along the route. This gives proxy infrastructure substantial influence over the transport characteristics visible to the target and is also relevant to passive OS fingerprinting.

From TCP's perspective, a proxy is an active transport endpoint with control over connection reuse, timeouts, routing, buffers, and outbound network behavior. For more on the application protocols carried across these connections, see our comparison of HTTP and SOCKS5 proxies.

Why TCP Still Works

TCP succeeded because it kept the same useful contract for applications while the control system underneath continued to evolve.

Slow start and congestion avoidance stabilized a growing internet. Window scaling made faster paths usable. SACK and RACK reduced the cost of packet loss. Pacing smoothed traffic. ECN provided earlier feedback. CUBIC and BBR gave senders different ways to estimate available capacity.

Most of these changes happened inside operating systems. Applications continued to receive the same reliable stream of bytes.

Newer transports such as QUIC address problems that are difficult to remove from TCP, including slow protocol updates inside operating-system kernels and head-of-line blocking between independent streams. QUIC still uses acknowledgments, loss detection, packet pacing, and congestion control. Our article on HTTP/3, QUIC, and proxies explains that newer transport model.

The format of a TCP connection is relatively simple. The decades of feedback loops controlling its speed, reliability, and recovery are what allowed it to keep up with the modern internet.

FAQ

Got questions?
We've got answers.

Quick answers to the most common questions about this topic.

TCP, or Transmission Control Protocol, is a transport protocol that provides reliable, ordered delivery of data between applications. It establishes a connection, tracks transmitted bytes, acknowledges received data, retransmits missing data, and adjusts its sending rate based on network conditions.

TCP uses a three-way handshake to establish a connection between two endpoints before data is transferred. The client sends a SYN, the server responds with SYN-ACK, and the client replies with ACK. This confirms that both sides are ready to communicate.

TCP congestion control determines how much data a sender can safely transmit without overwhelming the network. Algorithms adjust the congestion window based on signals such as acknowledgments, packet loss, round-trip time, and ECN congestion notifications.

CUBIC primarily discovers available capacity by increasing its congestion window until the network provides a congestion signal such as packet loss or ECN. BBR instead builds a model using measurements such as delivery rate and round-trip time and uses packet pacing to send near the estimated capacity of the path. Neither algorithm is universally faster, and performance depends on the network conditions.

When TCP detects missing data, it must retransmit it and may reduce its sending rate if the loss indicates congestion. Modern mechanisms such as SACK, RACK, and Tail Loss Probe help TCP identify and recover from lost packets more efficiently.

Packet pacing spreads transmitted packets more evenly over time instead of sending an entire congestion window in a sudden burst. This can reduce queue spikes, packet loss, and unnecessary latency.

With conventional HTTP CONNECT or SOCKS5 CONNECT proxying, the client establishes one TCP connection to the proxy and the proxy establishes another TCP connection to the destination. Each connection can independently respond to its own latency, packet loss, congestion, and available bandwidth. The destination generally observes the TCP/IP characteristics of the proxy's outbound connection rather than those of the original client.

HTTP/3 does not use TCP. It runs over QUIC, which uses UDP as its underlying transport. However, QUIC still implements concepts familiar from modern TCP, including acknowledgments, loss detection, packet pacing, and congestion control.

Ready to launch?

Proxies built for real operations.

For teams that depend on stability, not luck.