Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

System Design (High-Level Design)  Module 4 – Networking for system designers

TCP, QUIC, HTTP/1.1 to HTTP/3 and TLS 1.3

How TCP, UDP and QUIC differ, why HTTP/1.1, HTTP/2 and HTTP/3 stall on packet loss in different ways, what TLS 1.3 saves, and when 0-RTT is safe.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot

What you will learn

  • Compare TCP and UDP for request-response and streaming traffic
  • Explain head-of-line blocking in HTTP/1.1, HTTP/2 and HTTP/3
  • Count the round trips before the first byte for each transport and TLS version
  • Weigh TLS 1.3 0-RTT against its replay risk

Before you start

On this page

TCP gives an application one reliable stream of bytes in order; UDP sends separate datagrams with no promises at all. HTTP/1.1 sends one request at a time on each TCP connection, so browsers open several. HTTP/2 interleaves many requests on one TCP connection, but because TCP delivers bytes strictly in order, one lost packet stalls all of them. HTTP/3 runs over QUIC, a transport built on UDP that keeps each stream in order on its own and folds the TLS 1.3 handshake into its own, so a new connection can carry a request after one round trip. TLS 1.3 itself needs one round trip where TLS 1.2 needed two, and its 0-RTT mode saves even that one, at the price that early data can be replayed by an attacker.

This lesson measures what each choice costs: a simulation of packet loss, a round-trip count for every way of opening a connection, and the rule for what may go into early data.

TCP and UDP: what each one promises

TCP opens a connection with a handshake and then delivers a byte stream: every byte arrives, in the order it was sent, with flow control so a fast sender does not swamp a slow receiver and congestion control so senders share the network (RFC 9293). The price of “in order” is that a byte cannot be handed to the application until every byte before it has arrived.

UDP sends each message as a datagram on its own, with as little mechanism as possible: delivery and duplicate protection are not guaranteed (RFC 768). The IETF’s guidelines for UDP say plainly that an application which needs reliable delivery must build it itself, and must also cope with duplicates that may arrive much later (RFC 8085).

TCP or UDP for application traffic
Criterion TCPUDP
Before the first data One round trip for the handshake, then TLSNothing: the first datagram carries data
Lost data Resent by TCPGone, unless the application resends it
Ordering One ordered byte stream per connectionNone: datagrams may arrive out of order, or twice
Congestion control Built inThe application's job
A change of network Breaks the connection, which is its addresses and portsNo connection to break; the application copes
When to choose Request-response traffic where every byte mattersDNS queries, live voice and video, game state: data that is useless if it comes late

UDP’s natural uses are the ones where waiting is worse than losing. A DNS query and its answer fit in one datagram each, so there is no connection to set up. In a live call, audio that arrives too late to be played is useless, so the application skips it rather than waiting for a copy; the same holds for the position of a player in a game.

QUIC is the reliability work done once, carefully, on top of UDP. Its packets travel inside UDP datagrams, which existing systems and networks already carry, so it could be deployed without changing them, yet it gives back what TCP provides, reliable delivery, ordering and congestion control, adds TLS 1.3, keeps each stream in order on its own, and lets a connection survive a change of network (RFC 9000). Most traffic that needs reliability should use TCP or QUIC instead of inventing its own on raw UDP.

HTTP/1.1, HTTP/2 and HTTP/3

The meaning of HTTP, its methods, status codes and headers, is the same in all three versions. What changes is how messages travel.

  • HTTP/1.1 keeps connections open for many requests by default, but on one connection it handles them one at a time. Pipelining lets a client send several requests without waiting, yet the server must return the responses in the order the requests came, so one slow response holds up the rest. Clients therefore open several connections to a server, and the standard no longer fixes how many, asking clients to be conservative (RFC 9112).
  • HTTP/2 splits messages into binary frames, so many requests and responses interleave on one connection, and it compresses headers. Its own specification notes what it leaves unsolved: TCP head-of-line blocking (RFC 9113). HTTP/2’s streams are invisible to TCP, so a lost packet stalls every stream with data behind it.
  • HTTP/3 maps the same semantics onto QUIC. When a packet is lost, only the streams with data in that packet wait for the copy; the others carry on (RFC 9000). Even header compression was redesigned for this: HTTP/2’s scheme assumes headers arrive in order, so HTTP/3 uses QPACK, which is built to cause far less head-of-line blocking (RFC 9204).
Four packets, one lost: over TCP the packets behind the loss wait; over QUIC only the stream that lost a packet waits.HTTP/2 over TCPHTTP/3 over QUICPacket 1, stream AdeliveredPacket 2, stream Blost, resent a round trip laterPacket 3, stream Carrived, waits for packet 2Packet 4, stream Aarrived, waits for packet 2Packet 1, stream AdeliveredPacket 2, stream Blost, resent a round trip laterPacket 3, stream Cdelivered at oncePacket 4, stream Adelivered at once

The same loss, delivered by TCP and by QUIC

Text description of the diagram

Two columns show the same four packets in the order they were sent. Packets 1 and 4 belong to stream A, packet 2 to stream B and packet 3 to stream C. Packet 2 is lost and resent about a round trip later.

On the left, HTTP/2 over TCP: - packet 1 is delivered; - packet 2 is lost, and TCP must deliver bytes in order, so nothing behind it can be handed to HTTP/2; - packets 3 and 4 have arrived but wait for the resent packet 2, so streams A and C stall because of a loss in stream B.

On the right, HTTP/3 over QUIC: - packet 1 is delivered; - packet 2 is lost and resent; - packets 3 and 4 are delivered to streams C and A as soon as they arrive, because QUIC keeps each stream in order on its own. Only stream B waits for its lost packet.

A server can advertise HTTP/3 with an Alt-Svc response header that names the h3 protocol, and a client that receives it may try QUIC for its next connections. Some networks block UDP; then a client should fall back to a TCP-based version of HTTP (RFC 9114), which is why servers keep HTTP/2 running beside HTTP/3.

Head-of-line blocking, simulated

How much does one ordered stream cost? This simulation sends 20 responses of 10 packets each, interleaved, over a path with a 100 ms round trip, and drops packets at random. It measures when each response is complete when the receiver must deliver everything in order (HTTP/2 over TCP) and when each response is ordered on its own (HTTP/3 over QUIC). The round trip, the sending rate and the time to notice a loss are assumptions, written at the top:

One ordered stream against independent streams Python · hol_blocking_sim.py
"""Head-of-line blocking: 20 responses sent over one ordered byte stream (HTTP/2 over TCP) or as independent streams
(HTTP/3 over QUIC), with random packet loss. Seeded, so every run prints the same numbers."""
import random
from statistics import median, quantiles

STREAMS = 20             # 20 responses requested at once, as a page or an app screen does
PACKETS_PER_STREAM = 10  # about 12 KB each, in packets of about 1,200 bytes
RTT_MS = 100             # assumption: a round trip on a mobile network
GAP_MS = 0.5             # assumption: one packet leaves every 0.5 ms (about 19 Mbit/s)
TRIALS = 300


def completion_times(loss, rng):
    """When each stream's last byte reaches the application, for both kinds of delivery (milliseconds)."""
    # The sender interleaves the streams' packets, one of each in turn, as HTTP/2 and HTTP/3 servers commonly do.
    order = [(i % STREAMS, i // STREAMS) for i in range(STREAMS * PACKETS_PER_STREAM)]
    arrival = []
    for i in range(len(order)):
        sent = i * GAP_MS
        arrive = sent + RTT_MS / 2
        if rng.random() < loss:
            # Assumption: the loss is noticed one round trip after sending, and the copy takes half a round trip.
            arrive = sent + RTT_MS + RTT_MS / 2
        arrival.append(arrive)

    # Ordered: TCP hands bytes to HTTP/2 strictly in order, so a packet waits for every packet sent before it.
    ordered, ready = {}, 0.0
    for (stream, _), arrive in zip(order, arrival):
        ready = max(ready, arrive)
        ordered[stream] = ready
    # Independent: QUIC orders each stream on its own, so a packet waits only for its own stream's earlier packets.
    independent, ready_per_stream = {}, {}
    for (stream, _), arrive in zip(order, arrival):
        ready_per_stream[stream] = max(ready_per_stream.get(stream, 0.0), arrive)
        independent[stream] = ready_per_stream[stream]
    return ordered, independent


rng = random.Random(7)
print(f"{STREAMS} responses of {PACKETS_PER_STREAM} packets, round trip {RTT_MS} ms, {TRIALS} trials per loss rate")
print("Time until a response is complete, in ms, over all responses:")
print(f"{'':>5}  {'one ordered stream':>18}  {'independent streams':>19}")
print(f"{'loss':>5}  {'median':>8} {'p95':>9}  {'median':>9} {'p95':>9}  {'waited for another response':>27}")
for loss in (0.0, 0.005, 0.01, 0.02, 0.05):
    ordered_all, independent_all, waited = [], [], 0
    for _ in range(TRIALS):
        ordered, independent = completion_times(loss, rng)
        ordered_all += ordered.values()
        independent_all += independent.values()
        waited += sum(ordered[s] > independent[s] for s in range(STREAMS))
    p95 = lambda xs: quantiles(xs, n=20)[-1]
    share = waited / (TRIALS * STREAMS)
    print(
        f"{loss:>5.1%}  {median(ordered_all):>8.0f} {p95(ordered_all):>9.0f}  "
        f"{median(independent_all):>9.0f} {p95(independent_all):>9.0f}  {share:>27.0%}"
    )

Output

20 responses of 10 packets, round trip 100 ms, 300 trials per loss rate
Time until a response is complete, in ms, over all responses:
       one ordered stream  independent streams
 loss    median       p95     median       p95  waited for another response
 0.0%       145       149        145       149                           0%
 0.5%       170       240        145       150                          57%
 1.0%       206       244        146       196                          78%
 2.0%       228       245        146       223                          91%
 5.0%       237       246        148       239                          92%

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 hol_blocking_sim.py

With no loss the two are identical: the last packet arrives about 150 ms after the first left. With loss they part quickly. At 1 % loss, a response had only about a one-in-ten chance of losing one of its own 10 packets, yet over the ordered stream 78 % of the responses finished late, because some other response’s packet was lost ahead of theirs. The median response took 206 ms instead of 146. The independent streams’ 95th percentile also rises with loss, but only because those responses lost a packet of their own.

The model is simple on purpose: one stream’s data per packet, and every loss noticed one round trip after sending. Real QUIC packets may carry frames of several streams, and a lost packet then blocks all of them, so QUIC’s own specification advises senders to put as few streams in a packet as they can without wasting space.

Handshakes, counted in round trips

The previous lesson measured round trips of 9, 140 and 293 ms. What a new connection costs is a count of round trips times that number:

  • TLS 1.2 needs two round trips for a full handshake, and one when a client resumes an earlier session (RFC 5246).
  • TLS 1.3 needs one: the client’s first message carries its key share, and the server can finish its side in its first answer. A HelloRetryRequest, as in the previous lesson’s Japanese server, adds a round trip (RFC 8446).
  • QUIC runs its own handshake and TLS 1.3’s together, so the client can send its request after one round trip (RFC 9001). A server that wants proof that the client really is at its address first can answer with a Retry packet, which costs one more; until the address is proven, a server may send no more than three times the bytes it has received, so it cannot be used to flood someone else (RFC 9000).
Round trips before the first byte, and what they cost Python · handshake_rtt.py
"""Round trips before the first byte of a response, for each way of opening a connection, and what they cost at the
three round-trip times measured in the previous lesson."""

# (setup, round trips spent on handshakes before the request can leave). The request and its response then cost
# one more round trip. With 0-RTT early data the request leaves with the client's first TLS message.
SETUPS = [
    ("TCP + TLS 1.2, full handshake", 1 + 2),
    ("TCP + TLS 1.2, resumed session", 1 + 1),
    ("TCP + TLS 1.3", 1 + 1),
    ("TCP + TLS 1.3 after a HelloRetryRequest", 1 + 2),
    ("TCP + TLS 1.3, 0-RTT early data", 1 + 0),
    ("QUIC, TLS 1.3 built in", 1),
    ("QUIC after a Retry for address checks", 1 + 1),
    ("QUIC, 0-RTT early data", 0),
    ("An open connection, reused", 0),
]
RTTS_MS = {"at 9 ms": 9, "at 140 ms": 140, "at 293 ms": 293}  # near, Japan, Australia

print(f"{'setup':<42}{'round trips':>12}" + "".join(f"{name:>11}" for name in RTTS_MS))
for name, handshakes in SETUPS:
    trips = handshakes + 1
    print(f"{name:<42}{trips:>12}" + "".join(f"{trips * rtt:>8} ms" for rtt in RTTS_MS.values()))

Output

setup                                      round trips    at 9 ms  at 140 ms  at 293 ms
TCP + TLS 1.2, full handshake                        4      36 ms     560 ms    1172 ms
TCP + TLS 1.2, resumed session                       3      27 ms     420 ms     879 ms
TCP + TLS 1.3                                        3      27 ms     420 ms     879 ms
TCP + TLS 1.3 after a HelloRetryRequest              4      36 ms     560 ms    1172 ms
TCP + TLS 1.3, 0-RTT early data                      2      18 ms     280 ms     586 ms
QUIC, TLS 1.3 built in                               2      18 ms     280 ms     586 ms
QUIC after a Retry for address checks                3      27 ms     420 ms     879 ms
QUIC, 0-RTT early data                               1       9 ms     140 ms     293 ms
An open connection, reused                           1       9 ms     140 ms     293 ms

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 handshake_rtt.py

At 293 ms a full TLS 1.2 handshake over TCP spends 1,172 ms before the first byte, TCP with TLS 1.3 879 ms, and QUIC 586 ms. On a nearby path the same counts cost 36, 27 and 18 ms, which is why the gains of HTTP/3 and TLS 1.3 are largest for users far from the server or on slow mobile links, and small inside one data centre.

SSL Certificate Checker Check a site's certificate chain, which is what the server sends in the TLS handshake for the client to verify.

0-RTT: faster, but it can be replayed

A client that connected to a server before can keep a ticket from that session. On its next connection it can resume with that key and send data in its very first message, before any round trip: 0-RTT, or early data. The first byte of the response then arrives one round trip after TCP’s handshake, or after a single round trip with QUIC.

The price is in the TLS 1.3 specification: early data is not forward secret, and there is no guarantee that it is not replayed between connections (RFC 8446). An attacker who records the first flight can send it again, and the server may act on the same request twice. QUIC’s 0-RTT has the same weakness (RFC 9001).

HTTP turns this into rules (RFC 8470):

  • The client decides what to risk. Absent other information, a client may send requests with safe methods such as GET and HEAD in early data, and must not send unsafe ones. That rule is stricter than “idempotent”: PUT and DELETE are idempotent but unsafe, so they stay out.
  • The server decides per resource. Some resources have side effects even on GET, so the origin server knows best. A server can refuse early data altogether, hold a request until the handshake completes, or answer 425 Too Early, which tells the client to send the request again without early data.
  • Gateways pass the warning on. A proxy that forwards a request before its own handshake with the client is done must add the header Early-Data: 1, so the origin can still answer 425.

In a design, that means 0-RTT is worth having for read-only traffic such as page loads and catalogue reads, and is kept away from logins, payments and anything that changes state, unless the endpoint is protected against running twice in its own right.

Mobile networks and connection migration

TCP identifies a connection by the addresses and ports at both ends. When a phone moves from Wi-Fi to mobile data, its address changes and every TCP connection breaks; the app pays new handshakes and resends what was in flight. QUIC identifies a connection by connection IDs instead, so a client can move a connection to a new network path, and it also survives NAT rebinding, when a router on the path changes the address or port it uses for the device (RFC 9000). For a service whose users ride trains and buses between networks, that is a real gain on top of the faster handshake.

HAR File Analyzer & Sanitizer A HAR file records the protocol of every request, so you can see which ones used HTTP/1.1, HTTP/2 or HTTP/3.

What to choose in a design

  • At the edge, facing users: serve HTTP/2 and HTTP/3 with TLS 1.3, advertise HTTP/3 with Alt-Svc, and keep the TCP versions for clients and networks that cannot use UDP.
  • Between services inside a data centre: long-lived HTTP/2 connections are usually enough. Round trips are short there and connections stay open for a long time, so the handshake savings of HTTP/3 matter little; reusing connections matters more.
  • For 0-RTT: allow it only for safe requests whose replay does no harm, and make sure every gateway in the path understands 425 Too Early.
  • For real-time media and DNS: UDP, or a protocol built on it. For anything else that needs reliability, use TCP or QUIC rather than a home-made protocol.
HTTP Header Checker See a server's response headers, including the Alt-Svc header that advertises HTTP/3.

Interview questions

Warm-up (mid level): what is head-of-line blocking, and which versions of HTTP suffer from it? Head-of-line blocking is when one delayed item holds up everything queued behind it. HTTP/1.1 has it at the application level: responses on a connection come back in request order, so one slow response delays the rest, which is why browsers open several connections. HTTP/2 removes that by interleaving streams on one connection, but it runs over TCP, which delivers bytes in order, so one lost packet stalls every stream until it is resent. HTTP/3 runs over QUIC, which orders each stream on its own: a loss delays only the streams whose data was in the lost packet. A strong answer adds the evidence: at 1 % loss in this lesson’s simulation, 78 % of the responses on one ordered stream finished late because of another response’s loss.

Key takeaways

  • TCP delivers one ordered byte stream; UDP delivers datagrams with no promises; QUIC builds reliable, encrypted, independently ordered streams on top of UDP.
  • HTTP/1.1 blocks at the application level, HTTP/2 at the TCP level, and HTTP/3 only per stream.
  • In the simulation, 1 % packet loss made 78 % of the responses on one ordered stream late; independent streams kept the median at 146 ms against 206 ms.
  • Before the first byte: four round trips with TCP and full TLS 1.2, three with TLS 1.3, two with QUIC or with TCP and TLS 1.3 early data, and one with QUIC’s 0-RTT or a reused connection.
  • 0-RTT early data can be replayed: send only safe requests in it, and let servers refuse with 425 Too Early.
  • QUIC connections survive a change of network; TCP connections do not.

Exercise

Exercise · Easy · Python

Count the round trips before the first byte

Write round_trips(transport, tls, resumed=False, early_data=False) in round_trips.py. It returns how many round trips pass before the first byte of the response to an HTTPS request on a new connection:

- transport is "tcp" or "quic". TCP's handshake costs one round trip before TLS can start. QUIC runs its handshake and TLS's together, in one round trip. - tls is "1.2" or "1.3". Over TCP, a full TLS 1.2 handshake costs two round trips and a resumed TLS 1.2 session one; TLS 1.3 costs one round trip, resumed or not. QUIC always uses TLS 1.3. - early_data=True means the request rides in the client's first TLS message (0-RTT), so TLS adds no round trip of its own before the request. It needs a resumed TLS 1.3 session. - The request and its response always cost one more round trip.

Raise ValueError for anything that cannot happen: another transport or TLS version, QUIC with TLS 1.2, or early data without a resumed TLS 1.3 session.

round_trips("tcp", "1.2")                                  # 4
round_trips("quic", "1.3", resumed=True, early_data=True)  # 1

The sample tests import round_trips from round_trips.py and run in your browser.

Starter code · round_trips.py

def round_trips(transport, tls, resumed=False, early_data=False):
    """Round trips before the first byte of the response on a new connection."""
    # Replace this line with your code.
    return 0
The sample tests · test_round_trips.py
from round_trips import round_trips


def raises_value_error(call):
    try:
        call()
    except ValueError:
        return True
    return False


def test_tcp_and_tls_12():
    """a full TLS 1.2 handshake costs two round trips, a resumed one costs one"""
    assert round_trips("tcp", "1.2") == 4
    assert round_trips("tcp", "1.2", resumed=True) == 3


def test_tcp_and_tls_13():
    """TLS 1.3 costs one round trip, and none before the request with early data"""
    assert round_trips("tcp", "1.3") == 3
    assert round_trips("tcp", "1.3", resumed=True) == 3
    assert round_trips("tcp", "1.3", resumed=True, early_data=True) == 2


def test_quic():
    """QUIC combines its handshake with TLS 1.3"""
    assert round_trips("quic", "1.3") == 2
    assert round_trips("quic", "1.3", resumed=True) == 2
    assert round_trips("quic", "1.3", resumed=True, early_data=True) == 1


def test_impossible_combinations():
    """raises ValueError for what cannot happen"""
    assert raises_value_error(lambda: round_trips("udp", "1.3"))
    assert raises_value_error(lambda: round_trips("tcp", "1.1"))
    assert raises_value_error(lambda: round_trips("quic", "1.2"))
    assert raises_value_error(lambda: round_trips("tcp", "1.3", early_data=True))
    assert raises_value_error(lambda: round_trips("tcp", "1.2", resumed=True, early_data=True))
A hint

Check the arguments first and raise ValueError for the impossible combinations. Then add up three parts: the transport's own handshake (1 for TCP, 0 for QUIC, whose handshake is counted with TLS), the TLS round trips before the request can leave (0 with early data), and 1 for the request and its response.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

7 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 7 An HTTP/2 connection carries 20 responses at once over TCP, and one packet of response B is lost. What happens to the other 19 responses until the packet is resent?

    Choose one answer.

    Show the answer to question 1

    Answer: Every byte sent after the lost packet waits, so most of the other responses stall too

    TCP hands bytes to the application strictly in order. HTTP/2's streams are invisible to TCP, so the bytes of every stream that arrived after the lost packet wait for its copy. That is TCP head-of-line blocking, which HTTP/2 does not address.

  2. Question 2 of 7 Absent other information, which requests may a client send in TLS 1.3 early data (0-RTT), by the rules for HTTP?

    Choose every answer that is right.

    Show the answer to question 2

    Answer:

    • HEAD /reports/q3.pdf
    • GET /products?page=2

    Early data can be replayed, so a client may send only requests with safe methods such as GET and HEAD in it, and must not send unsafe methods. PUT and DELETE are idempotent, but they are not safe, so they stay out too.

  3. Question 3 of 7 How many round trips pass before the first byte of the response on a new connection with TCP and a full TLS 1.2 handshake?

    Type a number.

    Show the answer to question 3

    Answer: 4 round trips

    One for TCP, two for the full TLS 1.2 handshake, and one for the request and its response. TLS 1.3 saves one of them, and QUIC saves another by running its handshake together with TLS.

  4. Question 4 of 7 A phone moves from Wi-Fi to mobile data in the middle of a download. What happens to the connection?

    Choose one answer.

    Show the answer to question 4

    Answer: The TCP connection breaks, because it is tied to the old address and port; a QUIC connection can move to the new path using its connection IDs

    TCP identifies a connection by the two addresses and ports, so a new client address means a new connection and new handshakes. QUIC identifies it by connection IDs, which lets a client migrate the connection to a new network path once the handshake is confirmed.

  5. Question 5 of 7 An HTTP/3 client cannot reach a server because a firewall on the user's network blocks UDP. What should the client do?

    Choose one answer.

    Show the answer to question 5

    Answer: Fall back to HTTP/2 or HTTP/1.1 over TCP

    The HTTP/3 standard asks clients to try a TCP-based version of HTTP when a QUIC connection cannot be set up, for example because UDP is blocked. That is why servers keep serving HTTP/2 next to HTTP/3.

  6. Question 6 of 7 A team plans its own request-response protocol on raw UDP to avoid TCP's handshake. What is the strongest reason to reconsider?

    Choose one answer.

    Show the answer to question 6

    Answer: They would have to build retransmission, ordering, duplicate handling and congestion control themselves, which QUIC already provides

    UDP delivers datagrams with no retransmission, no ordering and no duplicate protection, so an application that needs reliable delivery must implement it. QUIC is exactly that work done carefully on top of UDP, with TLS 1.3 and congestion control included.

  7. Question 7 of 7 In the simulation's recorded output, what percentage of the responses on one ordered stream waited for another response's lost packet at 1 % packet loss?

    Type a number.

    Show the answer to question 7

    Answer: 78 %

    At 1 % loss, 78 % of the responses finished later over one ordered stream than they would have as independent streams, although each response had only about a one-in-ten chance of losing a packet of its own.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.