QUIC报文格式详解
QUIC的packet分為Special Packets和Regular Packets兩種,其中各自又有兩種不同的packet
特殊報文:
版本協商報文(Version Negotiation Packets)
公共重置報文(Public Reset Packets)
普通報文:
常規報文(Regular Packets)
FEC(Forward Error Correction)報文
QUIC報文的大小需要滿足路徑MTU (最大傳輸單元Maximum Transmission Unit) 的大小以避免被分片。當前QUIC在IPV6下的最大報文長度為1350,IPV4下的最大報文長度為1370.
所有的Quic包都是以一個1~51字節的公共頭開始的。其格式如下
紅色部分是認證的報文頭部,綠色部分是加密的報文內容
QUIC Public Packet Header
其中最重要的就是Public Flags,占一個字節,8個bit
0x01: 如果Bit0位被置為1, 0x01 = PUBLIC_FLAG_VERSION) ,該字段的含義取決于報文是客戶端發送的還是服務端發送的。如果是客戶端發送,這一位被置上表示QUIC Version字段不為空,且QUIC Version字段被填充為客戶端的QUIC版本。在客戶端收到服務端同意建立該版本的連接報文之前,客戶端發送的所有報文的這一位都必須被設置。如果服務端同意建立該版本的連接,那么之后這一位就不用設置了。
如果這一位是被服務端發送的報文設置的,那么就表示該報文是版本協商報文(Version Negotiation Packet)
0x02: 如果Bit1被置上 (0x02 = PUBLIC_FLAG_RESET),表明該報文是公共重置報文(Public Reset packet)
0x04: Bit2被置上就表示包頭包含了32字節的 Diversification Nonce
0x08: Bit3被置上就表示header中包含8字節的connection id 這個標志位在所有的包中都應該被設置
在0x30上的兩位(Bit4,Bit5)表示packet number 的長度,只有在含有Frame Packets的時候這兩位才會使用到,也就是說Reset 包和版本協商包都是不需要packet number的 (因為packet number是為了解決TCP重傳歧義性的問題)
- 0x30(Bit5及Bit4均為1)表示:packet number是6個字節
- 0x20(Bit5為1,Bit4為0)表示:packet number是4個字節
- 0x10(Bit5為0,Bit4為1)表示:packet numbe是2個字節
- 0x00(Bit5及Bit4均為0)表示:packet numbe是1個字節
0x40: Bit6 是預留給多路徑使用的
0x80: Bit7未使用,必須置為0
connection ID: 64位無符號整型,由client隨機產生,用來標識一個連接, 之所以使用Connection ID而不使用四元組標識(源 IP,源端口,目的 IP,目的端口),是為了就算 IP 或者端口發生變化時,只要 ID 不變,這條連接依舊可以維持,上層業務邏輯感知不到變化,不會中斷,也就不需要重連。
Quic Version : 32位,用來表示Quic 協議版本.只有當PUBLIC_FLAG_VERSION 被設置才會存在這個字段。server 只有在不支持客戶端攜帶的版本時,才會設置PUBLIC_FLAG_VERSION并且其后不會再附帶其他信息(也就是版本協商包)。
Packet Number : 可能為8,16,32,48位的packet number,具體的長度由public flags決定 。每個常規包(Regular Packet)都會被分配一個packet number, 各端發送的第一個包的packet number是1,之后的數據包中的packet number都會大于前一個包的packet number(單調遞增)
Public Flags的解析流程如下:
版本協商包報文
版本協商報文只能由服務端發送。版本協議報文以1字節的Public Flag及8字節的Connection ID開始。且public flag 必須置為PUBLIC_FLAG_VERSION,并標識Connection ID長度為8字節,剩下的部分,每4個字節表示server端 所支持的Quic版本信息
公共重置包 (Public Reset Packet)
Reset packets are sent by a server that does not have state for the connection, which may happen due to a routing change or due to a server restart.
Public Reset Packet的public flags必須設置PUBLIC_FLAG_RESET且標識Connection ID長度為8字節,剩余的部分是QUIC Tag。
Tag value map包含如下的tag-values:
RNON (public reset nonce proof):64位的無符號整數,必填
RSEQ (rejected packet number) :64位,必填
CADR (client address):客戶端的IP地址及端口。當前用于調試用途,可選
Regular Packet
常規包是經過認證和加密的,公共頭(Public Header)只經過認證,并沒有加密,包的剩余部分都是經過加密的。一個常規包會包含一系列的Frames
幀包有一系列不同的類型, 一般幀包的格式如下:
也分為普通幀包和特殊幀包
Stream Frame
STREAM Frame既用于隱式創建一條流,也用于發送數據,格式如下
Stream Frame的type是1fdooossB,這是一個8bit的值,包含各種flags
最左邊的bit 必須設置為1,表示這是一個STREAM frame, ‘f’ bit位表示 Fin 位,當該位被設置為1時,表示發送方已經發完了,連接將處于半關閉狀態。‘d’ bit表示在STREAM header中是否包含有數據長度,
當被設置為0時,表示 直到包尾都是STREAM Frame,后續的三個’ooo’bit表示Offset 長度,分別為 0,16,24,32,40,48,58,64位 ,再接下來的兩個’ss’表示stream id的長度,取值為8,16,24,32
Stream ID: 可變的無符號整型,唯一區分這條流
Offset: 可變長度,表示這塊數據在整個stream 中的偏移。
Data Length: 可選的16位無符號整型,表示在這個stream frame中數據的長度。
WINDOW_UPDATE Frame
用于告知對端接收窗口增加了,如果Stream ID 等于0,表示這是Connection的流量控制,否則就是Stream級別的流量控制,表示在指定的流上應該增加其流量控制窗口
Frame Type:8bit,必須設置成0x04 ,表示是WINDOW_UPDATE Frame
Stream ID: 0表示是Connection級別的流量控制,非0則表示對應Stream ID的流級別的流量控制
Byte offset: 64位,表示指定流上數據的絕對偏移量。
FEC(Forward Error Correction) packet
QUIC為了減少數據包丟失時的重傳,傳遞數據包時還會帶上其他數據包的校驗信息,即將N個包的校驗和(異或)建立一個單獨的數據包發送
P=D1 xor D2 xor D3 … xor Dn (D1,D2,D3 … Dn為數據塊,P為校驗,xor為異或運算)
假如D3 數據包丟失,可以通過p和其他參數異或恢復出來。并且還可以用來校驗記錄的數據包的有效性。
其他版本的報文格式
上述的報文格式都基于version 43及以下的版本,后面的版本在報文格式方面有一些改動
Version 44- 48:
為了推進Google QUIC的IETF標準化,在version46之后發生了如下改動
將Header分成兩種不同的類型,在1RTT連接建立和版本協商成功之前的packets 使用Long Header,其余的時候Short-Header
主要是在Long Header中增加了一個Source Connection ID并對格式進行了一些調整
DCIL:Destination Connection ID Length
SCIL:Source Connection ID Length
參考資料;
version 43:
QUIC Wire Layout Specification
version 46:
Use IETF Packet Header Wire Format in Google QUIC
version 49:
https://tools.ietf.org/html/draft-ietf-quic-invariants-07
總結
以上是生活随笔為你收集整理的QUIC报文格式详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP的拥塞控制--慢启动,拥塞避免,快
- 下一篇: 使用drawio进行画图真的很方便(WE