許多應用程序,如遊戲和直播等場景,需要一種機制來盡可能快速地發送訊息,同時可以接受無序、不可靠的數據傳輸方式。本機應用程式雖然可以使用原始 UDP 套接字,但這些在 Web 上不可用,因為它們缺乏加密、擁塞控制、同意發送機制(以防止 DDoS 攻擊)。
通常,需要客戶端和伺服器之間進行雙向資料流交換的 Web 應用程式可以依賴 WebSockets ,一種與 Web 安全模型相容的基於訊息的協定。然而,由於WebSockets是一個單一的、可靠的、有序的訊息流,它會受到隊頭阻塞(HOLB)的影響,這意味著所有訊息都必須按順序發送和接收,即使它們是相互獨立的。
這使得WebSockets不太適合透過犧牲可靠性、流獨立性來提高效能的應用程式。
WebTransport 協議為此提供了一個單一的傳輸對象,該對象抽像出具有一組靈活功能的特定底層協議,包括可靠的單向、雙向流,以及不可靠的數據報能力。
WebTransport是使用 HTTP3 從伺服器傳送和接收資料的協定框架。類似於 WebSockets,但支援多流、單向流、無序傳輸,支援可靠和不可靠的資料傳輸方式。
WebTransport 是一個 Web API,底層使用 HTTP/3 協定實作雙向傳輸。它用於客戶端和 HTTP/3 伺服器之間的雙向通訊機制。支援透過資料報 API實現不可靠資料傳輸方式,支援串流 API 實現可靠資料傳輸。同時在客戶端、服務端不需要連線的場景下關閉已有連線。
2.1 資料封包方式
資料報方式適合傳送、接收不需要嚴格保證交付的數據。單一資料包的大小受到底層連接的最大傳輸單元限制,無法保證傳輸成功,如果成功傳輸,也可能以任意順序抵達。這些特性使資料報 API 成為低延遲、盡全力傳輸的理想選擇。可以將資料傳輸方式視為用戶資料封包協定 (UDP) 訊息,但經過加密和擁塞控制。
// 发送数据报 const writer = transport.datagrams.writable.getWriter(); const data1 = new Uint8Array([65, 66, 67]); const data2 = new Uint8Array([68, 69, 70]); // Uint8Array writer.write(data1); writer.write(data2); // 从服务器读取数据报 const reader = transport.datagrams.readable.getReader(); while (true) { const {value, done} = await reader.read(); // done则退出 if (done) { break; } // 值为 Uint8Array。 console.log(value); }
2.2 串流API方式
#串流API 提供可靠、有順序的資料傳輸,非常適合需要傳送或接收一個或多個有序資料流的場景。使用多個 WebTransport 流類似於建立多個 TCP 連接,但由於 HTTP/3 在底層使用了輕量級的 QUIC 協議,因此新建、關閉連接的成本較低。
發送流
// 发送Uint8Array const stream = await transport.createSendStream(); const writer = stream.writable.getWriter(); const data1 = new Uint8Array([65, 66, 67]); const data2 = new Uint8Array([68, 69, 70]); // 实例化Uint8Array writer.write(data1); writer.write(data2); try { await writer.close(); // 所有数据已经传输 // await writer.abort(); // 如果调用abort并非所有数据都写入 } catch (error) { console.error(`An error occurred: ${error}`); }
讀取流
async function readFrom(receiveStream) { const reader = receiveStream.readable.getReader(); while (true) { const {done, value} = await reader.read(); if (done) { break; } // 值为 Uint8Array console.log(value); } } const rs = transport.receiveStreams(); // 返回一个 ReadableStream,ReadableStream 的每个块又是一个 ReceiveStream // 用于读取服务器发送的 Uint8Array 实例 const reader = rs.getReader(); while (true) { const {done, value} = await reader.read(); if (done) { break; } // 值为 ReceiveStream 的一个实例 await readFrom(value); }
雙向流
雙向流可由伺服器或用戶端建立:
async function setUpBidirectional() { const stream = await transport.createBidirectionalStream(); // stream 是 WebTransportBidirectionalStream // stream.readable是ReadableStream const readable = stream.readable; // stream.writable是WritableStream const writable = stream.writable; }
可以使用WebTransport 實例的
receiveBidirectionalStreams() 方法偵聽伺服器建立的BidirectionalStream ,該方法傳回ReadableStream。該ReadableStream 的每個區塊又是一個 BidirectionalStream。
const rs = transport.receiveBidrectionalStreams();const reader = rs.getReader();while (true) { const {done, value} = await reader.read(); if (done) { break; } // value 是 BidirectionalStream // value.readable 是 ReadableStream // value.writable 是 WritableStream}
3.1 WebTransport發展歷程
WebTransport在2019年5月左右首次被提出,最新一次更新是在2023年1月24號,因此從更新時間、更新頻率來看,目前該協定仍處於變更期和快速發展期,但值得開發者持續關注。
3.2 瀏覽器支援
目前WebTransport的整體瀏覽器支援率達到了70.29%左右,Chrome>=97、Edge>=98、Opera> ;=83等主流瀏覽器都已經支持,除了Firefox,最新的111版本還沒有支援。
WebSockets 圍繞著單一、可靠、有序的訊息流建模,有許多的應用場景。當然,這些特性 WebTransport 的串流 API 也可以提供。相較之下,WebTransport 的資料封包 API 提供低延遲交付,但無法保證可靠性、傳輸順序,因此還不能直接取代 WebSocket。
但是,透過資料封包 API 或多個並發 Streams API 實例使用 WebTransport,不必擔心佇列阻塞等WebSockets經常遇到的問題。此外,在建立WebTransport新連線時還有效能優勢,因為底層 QUIC 握手比透過 TLS 啟動 TCP 更快。
但是,由於WebTransport技術尚未完全敲定,開發工具較少,生態不完善,可能還會持續一段時間。現在預測 WebTransport 是否會取代 Websockets 還為時過早,但第一批使用它的團隊完全有機會建立一些開創性的東西。雖然沒有迫切需要切換,但開發人員應該為未來的專案密切關注它,並準備好在最合適的情況下使用它。
本文主要和大家介紹一個全新的通訊協定WebTransport、如何使用、同時與Websockets做了一個比較。因為筆者並沒有直接使用過WebTransport,所以只是做了一個基礎介紹~
以上是瀏覽器支援WebTransport?它能取代WebSockets?的詳細內容。更多資訊請關注PHP中文網其他相關文章!