UDP and QUIC Transport Layer

On this page

UDP preserves datagram boundaries but does not guarantee delivery, ordering, or deduplication. QUIC uses UDP to carry its own encrypted packets, acknowledgments, and multi-stream mechanisms; it provides reliable streams and can also carry unreliable datagrams via extensions. When choosing between them, first clarify whether the business requires messages or byte streams, whether expiration and discarding are allowed, and how success is confirmed, rather than equating UDP with "fast" and QUIC with "never disconnecting."

QuestionCore Understanding
How large is a single UDP send?UDP length, IP length, and path MTU impose separate constraints.
Why does QUIC change packet numbers on retransmission?Packet numbers identify a single transmission; stream offsets identify data positions.
Does packet loss block all streams?Streams are ordered internally; across streams, there is no unified byte gap like in TCP.
Is 0-RTT truly zero-wait for the first time?State recovery is required, it may be rejected, and there is a replay risk.
Why might it continue after changing IP?CID, path validation, and migration rules work together.

UDP: Responsibilities Beyond the 8-Byte Header

The UDP header consists of four 16-bit fields: Source Port, Destination Port, Length, and Checksum. The Length field includes the 8-byte UDP header; the maximum value for standard fields is 65535. However, in IPv4 without options, it is also constrained by the total IP length, making the maximum UDP data 65535−20−8=65507 bytes. This protocol upper bound is far larger than what common paths can directly carry, so it is not recommended for applications to send datagrams this large. RFC 768: UDP

When MTU=1500 and there are no options/extension headers, IPv4 UDP data is at most 1472 bytes, and IPv6 is 1452 bytes; tunneling and QUIC's own overhead will further reduce this. If a UDP datagram is fragmented by IP, it typically requires successful reassembly of all fragments to deliver the datagram; losing one fragment may result in the loss of the entire datagram.

The zero checksum field in IPv4 UDP indicates that no checksum is provided; if the calculated result is actually zero, it should be sent as all 1s on the wire. IPv6 UDP requires a checksum by default, with specific exceptions for tunnels and jumbograms having independent rules; exceptions should not be treated as the default for ordinary applications. The checksum covers the pseudo-header and the UDP message but does not provide sender authentication.

Applications must also handle loss, out-of-order delivery, duplication, size probing, and congestion control. UDP connect can set local default peer and filtering socket behaviors, but it does not perform a TCP-style remote handshake; a successful send does not prove the peer received the data. Real-time services often prefer to discard already expired data, but sending load should still be controlled. RFC 8085: Guidelines for UDP Applications

QUIC's Four-Layer Objects

Do not confuse UDP datagrams, QUIC packets, frames, and application streams One UDP datagram: payload follows the 8 B UDP header QUIC Packet A: its own header and protection CRYPTO Frame Handshake bytes ACK Frame Acknowledged packet numbers QUIC Packet B: its own header and protection Frame Set Frames allowed by packet type and encryption level The diagram shows packet coalescing hierarchy; it does not dictate which frames must be in each packet; short-header packets lack an independent Length field and are placed at the end of the datagram during coalescing.
ObjectIdentifier/BoundaryFunction
UDP DatagramUDP LengthA single datagram carrier on the path; can carry multiple QUIC packets
QUIC PacketPacket Number, etc.Unit of transmission for encryption protection, acknowledgment, and loss detection
FrameFrame Type and specific fieldsSemantics such as STREAM, ACK, CRYPTO, flow control, or path validation
StreamStream ID and Byte OffsetIndependent ordered byte streams available to the application

One stream can span many packets, and one packet can also carry frames from multiple streams. After packet loss, the information needed for retransmission may be packaged into another packet and re-fragmented; therefore, it is not simply re-sending the old packet intact.

Long Header, Short Header, and Visible Information

QUIC v1 uses corresponding long headers for Initial, Handshake, and 0-RTT, and a short header for 1-RTT; Retry and Version Negotiation have special structures, so a fixed byte table cannot cover all types. Long headers carry information such as Version and Connection ID length; the purpose CID length in short headers depends on the connection context and cannot be fully parsed from an isolated packet grabbed at random. RFC 9000: Packet Formats

Packet Numbers on the wire are encoded with only the necessary lower bits and are recovered by the receiver in context. Some header fields are header-proTECTED and cannot be analyzed directly as plaintext markers before unprotecting. The QUIC Bit rules in the v1 baseline also have subsequent negotiated extensions, so the bit must be interpreted in conjunction with negotiation results. RFC 9287: QUIC Bit Extension

The Spin Bit is an optional measurement signal; endpoints may not provide it, and observation is affected by loss, reordering, and path conditions. It is not a universal clock that strictly "flips once per RTT" per endpoint based on a timer, nor does it reveal application request latency.

Is it the information or the original packet that is retransmitted?

First, only deliver packet 11; stream 4 already has deliverable data, while stream 0 remains empty. Then deliver packet 12, and finally send the late packet 10: the set of acknowledged packets increases, but the amount of unique stream data no longer increases. These two numbering spaces cannot be understood as merged.

Preparing the visual
Is it the information or the original packet that is retransmitted?

New packet numbers can carry data within the same stream interval. Receiver deduplication is based on stream offset, while packet acknowledgment is based on packet number; a gap in one stream does not prevent delivery in another.

Handshake and Encryption Levels

QUIC uses TLS 1.3 handshake messages and key negotiation, but it does not simply wrap TLS records onto the transport stream; CRYPTO frames carry handshake bytes at the corresponding encryption level. Initial, Handshake, 0-RTT, and 1-RTT have different protection and usage conditions. Initial keys can be derived from public information, so Initial packet protection does not equal confidentiality from network observers or completion of server authentication. RFC 9001: TLS and QUIC

The initial handshake can often start corresponding application communication after one round trip, but Retry, certificate size, packet loss, and scheduling will change the actual measured latency. Servers are subject to anti-amplification limits before verifying the client's address, typically sending at most three times the number of bytes received; this may limit sending all handshake data in one go.

The UDP datagram carrying Initial for the client must be extended to at least 1200 bytes, referring to the UDP payload, not exactly 1200 bytes after adding UDP/IP. Under IPv6 without extension headers, this corresponds to at least 1248 bytes for the IP packet, and the real path still needs to be considered. RFC 9000: Datagram Size and Address Validation

0-RTT: Sending Early Does Not Mean Getting All Guarantees Early

When resuming a connection, the client can send early data based on saved TLS resumption state and allowed transport parameters; first-time visitors cannot magically possess these conditions. The server may reject early data; the TLS accept signal determines the result, and QUIC has no REJECTED frame for this purpose. When rejected, the client handles the original early data according to the protocol and application interface; rejection cannot be treated as the business logic having been executed. RFC 9001: 0-RTT

0-RTT has replay risks; applications must judge operation semantics and replay protection in deployment. HTTP method names are not sufficient proof: a misimplemented GET may also have side effects. AEAD's key usage limit restricts cryptographic risks but does not provide business deduplication or limit the number of replays by attackers.

Stream Numbering and Flow Control: Limits are Cumulative Upper Bounds

The least significant bit of the Stream ID indicates the initiating endpoint (0 for client, 1 for server), the next bit indicates the direction (0 for bidirectional, 1 for unidirectional); the remaining high bits are the sequence number for that category. Therefore, IDs for each category increment by 4:

CategoryFirst Batch of IDs
Client-initiated Bidirectional0, 4, 8, 12
Server-initiated Bidirectional1, 5, 9, 13
Client-initiated Unidirectional2, 6, 10, 14
Server-initiated Unidirectional3, 7, 11, 15

The two sending directions of a bidirectional stream have their own byte offsets. MAX_STREAM_DATA constrains the cumulative sendable range for the corresponding stream direction, MAX_DATA constrains the cumulative usage of corresponding stream data within the connection, and MAX_STREAMS limits the number of streams that can be opened; these are not three interchangeable "buffer sizes". RFC 9000: Streams and Flow Control

For example, if the connection limit is 10000 B, and two streams have already used 4000 and 3000 B respectively, the connection has 3000 B remaining; if the target stream itself only has 1000 B remaining, new data is limited to at most this 1000 B. Retransmitting existing bytes does not consume new flow control quotas again. RESET_STREAM's final size also participates in relevant accounting; you cannot bypass the upper limit by constantly resetting.

Independent delivery across streams: sharing network resources, yet still having their own ordered gaps Stream 0 Stream 4 0~999 Arrived 1000~1999 Missing 2000~2999 Arrived 0~999 Arrived 1000~1999 Arrived 2000~2999 Arrived Stream 4 can be delivered continuously; the second half of Stream 0 waits to be filled. If the same lost packet carries data for two streams, both streams will be affected; connection congestion window and connection flow control are still shared.

Independent streams eliminate the cross-stream transport layer waiting caused by TCP's single ordered byte stream, but gaps within the same stream still need to be filled. Multiple streams share congestion control, connection flow control, CPU, and path; HTTP/3 may also have application-layer dependencies, so "QUIC has no head-of-line blocking at all" is still inaccurate.

Why does retransmission no longer occupy a flow control quota?

Drawing the connection total and the target stream separately reveals where the bottleneck lies. Keeping offsets unchanged and repeatedly retransmitting causes line-rate duplicate bytes to grow, but the flow control balance remains unchanged; this is not free bandwidth, and retransmissions are still subject to other constraints like congestion control.

Preparing the visual
Why does retransmission no longer occupy a flow control quota?

Quotas are accumulated based on the maximum offset consumed by each stream, not based on line-rate bytes sent repeatedly. New data is constrained by both connection and stream upper limits; retransmitting an existing interval does not increase the offset.

ACK and Loss Detection: Acknowledgment Does Not Equal Mind-Reading

Initial, Handshake, and Application Data are three Packet Number Spaces, where 0-RTT and 1-RTT share the application data space. Packet numbers increment and are not reused within their respective spaces; new packet numbers are used when stream bytes are repackaged for sending. ACK reports acknowledged packet number intervals and does not directly list a list of packets physically confirmed as lost.

If packet 10 is unacknowledged but a larger packet is acknowledged, it may be lost or simply out of order. RFC 9002 infers using packet thresholds and time thresholds, etc.; the recommended packet threshold is 3; the time reference is 9/8×max(latest_rtt,smoothed_rtt) considering clock granularity and other conditions, so that new samples and smoothed estimates jointly constrain the judgment. Judgment also requires context such as acknowledged packets sent later. RFC 9002: Loss Detection

PTO expiration schedules probes; it does not directly declare that all unacknowledged packets are lost. Taking a simplified estimate for the application data space as an example, with SRTT=40 ms, RTTVAR=5 ms, max_ack_delay=25 ms, and granularity 1 ms, the PTO base value is 40+max(20,1)+25=85 ms; the handshake space does not simply copy the same ACK delay, and consecutive PTOs have backoff.

Congestion control determines sending load, and recovery mechanisms determine which information to supplement. RFC 9002 provides an example congestion algorithm based on NewReno; QUIC does not require all implementations to use it; CUBIC, BBR, etc., can be adopted by implementations under protocol constraints.

CID and Migration: New Paths Still Require Verification

The receiver can associate packets from a new address to the connection using its own issued Connection ID. CIDs are not eternal, unchanging pairs of numbers; endpoints can issue, use, and retire multiple CIDs according to rules, and short headers do not carry both source and destination CIDs simultaneously. Deployment choices like zero-length CIDs will limit migration capabilities.

After the client changes networks, protected packets on the new path still require connection authentication and path verification; PATH_CHALLENGE's random data is echoed by PATH_RESPONSE, helping to confirm return path reachability. NAT port rebinding and active migration have different backgrounds, and parameters prohibiting active migration should not be simply understood as rejecting all address changes. RFC 9000: Migration and Verification

Paths may have new RTT, capacity, and MTU; related control states need to be handled according to rules, and business may pause or fail. Matching CIDs alone is not enough to promise "the application sees no interruption"; new paths not supporting UDP, lost key states, or verification timeouts may all prevent the connection from continuing.

Reliable STREAM and Unreliable DATAGRAM

The QUIC DATAGRAM extension preserves application datagram boundaries, does not retransmit lost data like STREAM, and does not use STREAM flow control; it is still subject to connection congestion control and negotiated size limits. Receiving an ACK for the packet carrying it does not mean the application has processed the message. Real-time data can choose expiration and discard semantics based on this, but it cannot be assumed that QUIC encryption guarantees reliable delivery. RFC 9221

HTTP/3, DoQ, etc., define their own application mappings for QUIC. Actual selection also depends on UDP reachability, implementation maturity, observability, and resource consumption; user-space implementations are convenient for evolution but do not automatically guarantee lower CPU usage than kernel TCP.

Local Recalculation: Numbering, Flow Control, and Probe Budgets

from math import isclose

def stream_id(index,server=False,unidirectional=False):
    return (index<<2) | int(server) | (int(unidirectional)<<1)
assert [stream_id(i) for i in range(4)] == [0,4,8,12]
assert [stream_id(i,True,True) for i in range(4)] == [3,7,11,15]
assert 65535-20-8 == 65507
assert 1200+8+40 == 1248
assert min(10000-4000-3000,1000) == 1000
assert 1200*3 == 3600
srtt,latest,rttvar,ack_delay,granularity = .040,.050,.005,.025,.001
loss_delay = max(granularity,9/8*max(srtt,latest))
pto = srtt+max(4*rttvar,granularity)+ack_delay
assert isclose(loss_delay,.05625)
assert isclose(pto,.085)
# Packet 10's content retransmitted into packet 14: stream offset unchanged, sending packet number different.
sent = {10:(0,1000,500),14:(0,1000,500)}
assert sent[10] == sent[14] and 10 != 14
print('UDP/Initial size, stream ID, quota, threshold, and PTO examples passed')

These assertions verify local fields and budgets; they do not implement complete packet protection, handshake, or loss detection state machines; no real QUIC connection or network migration is started.

Continue Reading

  • TCP: Byte sequence numbers, windows, and recovery comparisons.
  • Ports and NAT Traversal: Mapping, filtering, and path establishment.
  • HTTP/3: HTTP streams and application dependencies over QUIC.