目录
- Connection Establishment | 连接建立
- Data Transfer | 数据传输
- Life of a QUIC Stream | QUIC流的生命周期
- Connection Termination | 连接关闭
Life of a QUIC Connection | QUIC连接的生命周期
Connection Establishment | 连接建立
A QUIC client is the endpoint that initiates a connection. QUIC’s connection establishment intertwines version negotiation with the crypto and transport handshakes to reduce connection establishment latency. We first describe version negotiation below.
QUIC的客户端指的是发起连接的那个端。QUIC连接的建立是将编码过的版本协商和握手传输合并在一起来降低连接建立的时延。接下来我们先描述版本协商。
Each of the initial packets sent from the client to the server must set the version flag, and must specify the version of the protocol being used. Every packet sent by the client must have the version flag on, until it receives a packet from the server with the version flag off. After the server receives the first packet from the client with the version flag off, it must ignore any (possibly delayed) packets with the version flag on.
从客户端发往服务端的每一个初始化包都必须设置版本标志为1,并且必须指明所使用的协议的版本。客户端发送的每一个包都必须设置版本标志为1,直到客户端收到服务端发送的版本标志位0的包。服务端收到第一个版本标志位0的包之后,服务端会忽略所有(有可能是延时到达的)版本标志位1的包。
When the server receives a packet with a Connection ID for a new connection, it will compare the client’s version to the versions it supports. If the client’s version is acceptable to the server, the server will use this protocol version for the lifetime of the connection. In this case, all packets sent by the server will have the version flag off.
当服务端收到一个包含新连接的连接ID的包时,服务端会比较客户端的版本以及服务端支持的版本。如果服务端接受了客户端的版本,在整个连接的生命周期内,服务端会使用这个协议版本。在这种情况下,所有服务端发送的包都会把版本标志设置为0.
If the client’s version is not acceptable to the server, a 1-RTT delay will be incurred. The server will send a Version Negotiation Packet to the client. This packet will have the version flag set and will include the server’s set of supported versions.
如果客户端的版本不被服务端所接受,会引起一个1-RTT
的时延。服务器会发送一个版本协商包给客户端。这个包会设置版本标志为1并且包含了服务端所支持的所有版本。
When the client receives a Version Negotiation Packet from the server, it will select an acceptable protocol version and resend all packets using this version. These packet must continue to have the version flag set and must include the new negotiated protocol version. Eventually, the client receives the first Regular Packet (i.e. not a Version Negotiation Packet) from the server indicating the end of version negotiation, and the client now sends all subsequent packets with the version flag off.
当客户端收到版本协商包,客户端会选择一个可接受的协议版本并且使用这个新版本重新发送所有的包。这些包必须设置版本标志为1并且包含新的经协商的协议版本。最终,客户端接收到第一个常规包(换言之,不是协议协商包)表示版本协商结束,之后客户端发送的所有后续包都将版本标志设置为0。
In order to avoid downgrade attacks, the version of the protocol that the client specified in the first packet and the set of versions supported by the server must be included in the crypto handshake data. The client needs to verify that the server’s version list from the handshake matches the list of versions in the Version Negotiation Packet. The server needs to verify that the client’s version from the handshake represents a version of the protocol that it does not actually support.
为了避免版本降级攻击,客户端在第一个包中所指定的协议版本和服务端所支持的版本集合必须被包含在加密握手数据中。客户端需要验证握手中的服务器版本列表和版本协商包中的版本列表相匹配。服务端需要验证客户端是否真的支持握手中的版本。
The rest of the connection establishment is described in the handshake document [QUIC-CRYPTO]. The crypto handshake is performed over the dedicated crypto stream (Stream ID 1).
连接建立的剩余部分在握手文档[QUIC-CRYPTO]中描述。加密的握手过程发生在专用的加密stream中(流ID为1)。
During connection establishment, the handshake must negotiate various transport parameters. The currently defined transport parameters are described later in the document.
在连接建立的过程中,握手必须协商多种传输参数。目前已定义的传输参数会在文档的稍后部分描述。
Data Transfer | 数据传输
QUIC implements connection reliability, congestion control, and flow control. QUIC flow control closely follows HTTP/2’s flow control. QUIC reliability and congestion control are described in an accompanying document. A QUIC connection uses a single packet sequence number space for shared congestion control and loss recovery across the connection.
QUIC实现了可靠连接,拥塞控制和流量控制。QUIC的流量控制近似遵循HTTP/2的流量控制。QUIC的可靠性和拥塞控制在一个伴生文档中描述。一个QUIC连接使用一个独立的包序号空间来同时实现拥塞控制和丢包恢复。
All data transferred in a QUIC connection, including the crypto handshake, is sent as data inside streams, but the ACKs acknowledge QUIC Packets.
所有在QUIC连接上传输的数据,包括加密握手数据,都是作为流内的数据被发送,除了ACK包。
This section conceptually describes the use of streams for data transfer within a QUIC connection. The various frames that are mentioned in this section are described in the section on Frame Types and Formats.
这个部分从概念上描述如何使用连接上用于传输数据的流。本部分所提到的各种帧会在后续的帧类型和格式部分描述。
Life of a QUIC Stream | QUIC流的生命周期
Streams are independent sequences of bi-directional data cut into stream frames. Streams can be created either by the client or the server, can concurrently send data interleaved with other streams, and can be cancelled. QUIC’s stream lifetime is modeled closely after HTTP/2’s [RFC7540].
(HTTP/2’s usage of QUIC streams is described in more detail later in the document.)
流是双向都拥有独立序列封装在流类型帧的数据。流可以被客户端或服务端创建。多个流可以并行交替式的发送数据,流可以被取消。QUIC流的生命周期的模型类似于HTTP/2的[RFC7540]。
(HTTP/2如何使用QUIC流的在文档的稍后处详细描述)
Stream creation is done implicitly, by sending a STREAM frame for a given stream. To avoid stream ID collision, the Stream-ID must be even if the server initiates the stream, and odd if the client initiates the stream. 0 is not a valid Stream-ID. Stream 1 is reserved for the crypto handshake, which should be the first client-initiated stream. When using HTTP/2 over QUIC, Stream 3 is reserved for transmitting compressed headers for all other streams, ensuring reliable in-order delivery and processing of headers.
流的创建是通过在指定流上发送一个流类型帧隐式完成的。为了防止流ID碰撞,服务端初始化的流的流ID必须是偶数,客户端初始化的流的流ID必须是奇数。0不是一个可用的流ID。流ID为1保留用于加密握手,应该是第一个客户端初始化的流。如果使用HTTP/2 over QUIC,流 3保留用于传输所有其它流的压缩头部,保证头部按顺序传输和处理。
Stream-IDs from each side of the connection must increase monotonically as new streams are created. E.g. Stream 2 may be created after stream 3, but stream 7 must not be created after stream 9. The peer may receive streams out of order. For example, if a server receives packet 10 including frames for stream 9 before it receives packet 9 including frames for stream 7, it should handle this gracefully.
新流创建时,连接的两端的流ID都必须线性增长。比如ID为2的流可能在ID为3的流之后创建,但是ID为7的流必须不能在ID为9的流之后创建。对端可能收到乱序的流。比如,服务端先收到包序号为10从属于流ID为9的帧,再收到包序号为9从属于流ID为7的帧,服务器应该优雅处理这种情况。
If the endpoint receiving a STREAM frame does not want to accept the stream, it can immediately respond with a RST_STREAM frame (described below). Note, however, that the initiating endpoint may have already sent data on the stream as well; this data must be ignored.
如果一端收到了一条流的帧但是不想接收这条流,那么在这端可以立即回复一个RST_STREAM
帧(下面有描述)。注意,初始化的那端可能已经在这条流上发数据了,接收端应该忽略这些数据。
Once a stream is created, it can be used to send and receive data. This means that a series of stream frames can be sent by a QUIC endpoint on a stream until the stream is terminated in that direction.
如果一条流被创建了,它可以用来发送和接收数据。这意味着一系列的流类型帧数据可以被QUIC端在流上发送直到该方向上的流被关闭。
Either QUIC endpoint can terminate a stream normally. There are three ways that streams can be terminated:
QUIC的任意一端都可以正常的关闭流。流被关闭有三种方式:
- Normal termination: Since streams are bidirectional, streams can be “half-closed” or “closed”. When one side of the stream sends a frame with the FIN bit set to true, the stream is considered to be “half-closed” in that direction. A FIN indicates that no further data will be sent from the sender of the FIN on this stream. When a QUIC endpoint has both sent and received a FIN, the endpoint considers the stream to be “closed”. While the FIN should be sent with the last user data for a stream, the FIN bit can be sent on an empty stream frame following the last data on the stream.
- Abrupt termination: Either the client or server can send a RST_STREAM frame for a stream at any time. A RST_STREAM frame contains an error code to indicate the reason for failure (error codes are listed later in the document.) When a RST_STREAM frame is sent from the stream originator, it indicates a failure to complete the stream and that no further data will be sent on the stream. When a RST_STREAM frame is sent from the stream receiver, the sender, upon receipt, should stop sending any data on the stream. The stream receiver should be aware that there is a race between data already in transit from the sender and the time the RST_STREAM frame is received. In order to ensure that the connection-level flow control is correctly accounted, even if a RST_STREAM frame is received, a sender needs to ensure that either: the FIN and all bytes in the stream are received by the peer or a RST_STREAM frame is received by the peer. This also means that the sender of a RST_STREAM frame needs to continue responding to incoming STREAM_FRAMEs on this stream with the appropriate WINDOW_UPDATEs to ensure that the sender does not get flow control blocked attempting to deliver the FIN.
- Streams are also terminated when the connection is terminated, as described in the next section.
- 正常关闭: 由于流是双工的,所以流可以半关闭或者全关闭。当流的一端发送了一个FIN标志为1的帧,流在这个方向进入半关闭状态。FIN表示流上发送FIN的一方没有更多数据要发送了。如果QUIC端既发送了FIN又接收了FIN,那么这个流被认为全关闭状态。FIN应该在发送完流上的用户数据后发送,FIN标志可以用一个空帧发送。
- 强制关闭: 客户端和服务端都可以在任意时刻发送
RST_STREAM
帧。一个RST_STREAM
帧包含了一个标识失败原因的错误码(错误码列表在文档后续部分展示)。如果是流发起者发送RST_STREAM
帧,表示流发生了失败并且没有更多数据在流上发送。当流接收者发送RST_STREAM
,那么发送端应该停止在这条流上发送任何数据。流接收端应该注意这里有一个竞态条件,在发送端已经发送了的数据和RST_STREAM
帧被接收到的时间之间。为了确保连接级别的流量控制被正确统计,即使发送端已经收到了RST_STREAM
,发送端还必须确保流上的FIN和所有数据被对端接收了或者RST_STREAM
已经被对端发送了。这也意味着RST_STREAM
的发送者需要对这条流上的流类型帧保持回复(根据WINDOW_UPDATE
)来确保发送端不会被流量控制所阻塞而触发发送FIN。 - 连接关闭时,流也会被关闭,就像下面这部分描述的。
Connection Termination | 连接关闭
Connections should remain open until they become idle for a pre-negotiated period of time. When a server decides to terminate an idle connection, it should not notify the client to avoid waking up the radio on mobile devices. A QUIC connection, once established, can be terminated in one of two ways:
连接应该保持打开直到它们的空闲时间达到了之前协商的时间。当服务端决定关闭一个空闲连接,服务端不应该通知客户端以避免唤醒手机设备。一个QUIC连接一旦被建立了,可以被两种方式关闭:
- Explicit Shutdown: An endpoint sends a CONNECTION_CLOSE frame to the peer initiating a connection termination. An endpoint may send a GOAWAY frame to the peer prior to a CONNECTION_CLOSE to indicate that the connection will soon be terminated. A GOAWAY frame when sent signals to the peer that any active streams will continue to be processed, but the sender of the GOAWAY will not initiate any additional streams and will not accept any new incoming streams. On termination of the active streams, a CONNECTION_CLOSE may be sent. If an endpoint sends a CONNECTION_CLOSE frame while unterminated streams are active (no FIN bit or RST_STREAM frames have been sent or received for one or more streams), then the peer must assume that the streams were incomplete and were abnormally terminated.
- Implicit Shutdown: The default idle timeout for a QUIC connection is 30 seconds, and is a required parameter(“ICSL”) in connection negotiation. The maximum is 10 minutes. If there is no network activity for the duration of the idle timeout, the connection is closed. By default a CONNECTION_CLOSE frame will be sent. A silent close option can be enabled when it is expensive to send an explicit close, such as mobile networks that must wake up the radio.
- 显式关闭: 一端发送一个
CONNECTION_CLOSE
帧给对端标识一个连接的关闭。在发送CONNECTION_CLOSE
之前可能发送GOAWAY
帧来标识这个连接很快会被关闭。发送一个GOAWAY
帧用于通知对端目前所有活跃的流会继续工作,但是GOAWAY
的发送者不会再初始化任何其他的流并且不会再接收新的流。在活跃的流关闭时,可能会发送CONNECTION_CLOSE
。如果一端发送了CONNECTION_CLOSE
而还有未关闭的流是活跃的(一个或多个流上没有FIN标志也没有RST_STREAM
帧被发送或接收),那么对端必须假设这种流是不完整的并且被异常关闭了。 - 隐式关闭: QUIC连接的默认超时关闭时间是30秒,并且是在连接协商阶段的一个必须的参数(“ICSL”)。最大值是10分钟。如果在超时时间内没有网络活动,连接会被关闭。默认会发送一个
CONNECTION_CLOSE
帧。在发送显式关闭代价太大的情况下(比如说移动网络)可以开启静音关闭选项。
An endpoint may also send a PUBLIC_RESET packet at any time during the connection to abruptly terminate an active connection. A PUBLIC_RESET is the QUIC equivalent of a TCP RST.
一端也可以在连接的任意时刻发送一个PUBLIC_RESET
包来强制关闭一个活跃连接。QUIC的PUBLIC_RESET
和TCP的RST等价。
英文原文链接
QUIC Wire Layout Specification - Google 文档
本文完,作者yoko,尊重劳动人民成果,转载请注明原文出处: https://pengrl.com/p/36889/