QUIC operations
正如一開始介紹了,QUIC 在網路分層上雖然已經有點跨層次的感覺(整合傳輸層以及 TLS1.3),但使用上定位還是被歸類在傳輸層,一般情況下不會直接使用,而是依照上層應用層的協定來傳遞資料。
在 QUIC 的標準 RFC9000 裡面也有寫到,該文檔沒有定義 QUIC 的 API,而是定義的一系統的 operations 可以操作 QUIC 協定中的 stream 以及 connection 讓應用層協定可以依賴。
Operations on Streams
RFC9000 定義了以下針對 stream 的操作
對於傳送端
-
Write data: 對 stream 寫入資料,要配合 stream flow control 機制,只有在預留空間足夠時才能成功寫入。
-
End the stream(clean termination): 關閉一個 stream,結束時發送一個帶有 FIN 的 STREAM frame,實作時可能要考慮把該 stream 用到的資源也一併清除。
-
Reset the stream(abrupt termination): 透過 RESET_STREAM frame 將 stream 改為 terminal state。
對於接收端
-
Read data: 讀取資料
-
Abort reading of the stream: 可以透過 STOP_SENDING frame 通知對端中止傳送,並且關閉 stream。
當 stream 的狀態改變時,應用層協定可以請求收到通知,做相對應的處理。
很多 library 會設計成 callback function 的形式,上述事件發生時,除了處理 QUIC 本身的邏輯外,也可以讓開發應用層功能的人決定事件觸發時還要執行什麼額外的邏輯。
Operations on Connections
RFC9000 定義了以下針對 connection 的操作
以下的操作都是以應用層協定的角度來定義他們要怎麼運用 QUIC 協定
Client 端
- 主動開啟一個新的 connection
- 條件允許下啟用 Early Data (0-RTT)
當 Early Data 被 server 端拒絕時會收到通知或者處理。
Server 端
- Listen 傳入的 connection,負責 Handshake 交互流程
- 如果支援 Early Data,在回傳的 TLS resumption ticket 中嵌入應用層要的資料(application-controlled data)
- 如果支援 Early Data, 可以從用戶端傳來的 resumption ticket 中提取(retrieve)資料,並根據資料決定要接收還是拒絕
Client & Server 端都可以
- 通過 transport parameters 設置各種不同類型的 stream 的初始流個數的最小值
- 通過 flow control limits 控制接收緩衝區的資源分配
- 確認 handshake 流程是否完成,還是正在進行中
- 避免 connection 發生 silently close
- 生成 PING frame
- 在 idle timeout 之前請求發送其他 frame (之後介紹 Idle Timeout 時會說明)
- 有能力立刻關閉一個 connection
開源實現
目前有很多 QUIC 的開源實現,詳情可以參考 QUIC 開源實現列表,這篇文章整理了幾乎所有在 github 上面的開源 library,支援的版本欄位可能稍微過時了一些,自從 RFC9000 標準公佈後,大部分還有在維護的專案都支援 IETF 所提出的標準版本了。想要動手做實驗的讀者也可以找找自己常用的語言是否也有開源的 QUIC library。
這次鐵人賽我們會選擇 ngtcp2 來學習,ngtcp2 是一個由 c 寫的 library,會選他主要是因為這個專案算相對穩定,也有部份專案已經選用 ngtcp2,讓其應用程式可以享受 QUIC 帶來的好處(像是 curl 的 HTTP/3 擴充)。
明天的文章中,我們會簡單的帶各位讀者編譯 ngtcp2 的簡單範例,在還沒有深入了解協定之前,先試著把範例跑起來,後續的文章中會看 ngtcp2 的實現,並且搭配 RFC 來讀,把抽象的概念與具體的實現連結在一起。