使用 WebRTC 資料管道在瀏覽器之間傳送資料

在兩個瀏覽器之間傳送資料以進行通訊、玩遊戲或傳輸檔案,可能相當複雜。您必須設定並支付伺服器費用,才能轉送資料,而且可能需要將這項服務擴展到多個資料中心。在這種情況下,延遲時間可能會很長,而且難以確保資料隱私。

使用 WebRTC 的 RTCDataChannel API 直接在對等互連裝置之間傳輸資料,即可減輕這些問題。本文將說明如何設定及使用資料管道,以及目前網路上常見的用途。

為什麼要使用其他資料管道?

我們提供 WebSocketAJAX伺服器傳送事件。為什麼需要其他通訊管道?WebSocket 是雙向的,但所有這些技術都是為與伺服器之間的通訊而設計。

RTCDataChannel 採取不同做法:

  • 這項功能可搭配 RTCPeerConnection API 使用,實現點對點連線。這可縮短延遲時間,因為沒有中繼伺服器,且「躍點」較少。
  • RTCDataChannel 使用串流控制傳輸通訊協定 (SCTP),可設定傳送語意 (無序傳送和重新傳輸設定)。

Google Chrome、Opera 和 Firefox 的電腦版和 Android 版現已支援 SCTP,並提供「RTCDataChannel」功能。

注意事項:信號、STUN 和 TURN

WebRTC 可進行對等通訊,但仍需透過伺服器發出信號,交換媒體和網路中繼資料,以啟動對等連線。

WebRTC 會透過以下方式處理 NAT 和防火牆:

  • ICE 架構,在對等互連裝置之間建立最佳網路路徑。
  • STUN 伺服器,用於確認每個對等互連的公開 IP 和通訊埠。
  • TURN 伺服器 (如果直接連線失敗,且需要轉送資料)。

如要進一步瞭解 WebRTC 如何與伺服器搭配運作,進行信號傳輸和網路連線,請參閱「WebRTC in the real world: STUN, TURN, and signaling」。

功能

RTCDataChannel API 支援彈性資料類型集。這項 API 的設計完全仿效 WebSocket,並支援RTCDataChannel字串,以及 JavaScript 中的部分二進位類型,例如 BlobArrayBufferArrayBufferView。這類別在處理檔案傳輸和多人遊戲時相當實用。

RTCDataChannel 可在不可靠且無序的模式 (類似於使用者資料包通訊協定或 UDP)、可靠且有序的模式 (類似於傳輸控制通訊協定或 TCP),以及部分可靠模式下運作:

  • 可靠且依序模式可確保訊息傳輸,以及訊息傳送順序。這會增加額外負擔,因此這個模式可能會比較慢。
  • 不可靠且無序模式無法保證每封郵件都能送達另一端,也無法保證郵件送達的順序。這樣一來,就不會產生額外負擔,因此這個模式的運作速度會快上許多。
  • 部分可靠模式可確保在特定條件下傳輸訊息,例如重新傳輸逾時或重新傳輸次數上限。訊息順序也可設定。

如果沒有封包遺失,前兩種模式的效能大致相同。不過,在可靠且依序傳輸模式中,遺失的封包會導致其他封包遭到封鎖,且遺失的封包在重新傳輸並抵達時,可能已過時。當然,您可以在同一個應用程式中使用多個資料管道,每個管道都有自己的可靠或不可靠語意。

以下是 Ilya Grigorik 撰寫的《High Performance Browser Networking》一書中提供的實用表格:

TCPUDPSCTP
可靠性穩定可靠不可靠可自行設定
外送排序依據未排序可自行設定
變速箱以位元組為導向訊息導向訊息導向
流量控制
壅塞控制

接下來,您將瞭解如何設定 RTCDataChannel,以使用可靠且依序或不可靠且無序的模式。

設定資料管道

網路上有幾個簡單的 RTCDataChannel 示範:

在這些範例中,瀏覽器會與自身建立對等互連連線,然後建立資料管道,並透過對等互連連線傳送訊息。然後建立資料通道,並透過對等互連傳送訊息。最後,您的訊息會顯示在頁面另一側的方塊中!

開始使用這項功能的程式碼很短:

const peerConnection = new RTCPeerConnection();

// Establish your peer connection using your signaling channel here
const dataChannel =
  peerConnection.createDataChannel("myLabel", dataChannelOptions);

dataChannel.onerror = (error) => {
  console.log("Data Channel Error:", error);
};

dataChannel.onmessage = (event) => {
  console.log("Got Data Channel Message:", event.data);
};

dataChannel.onopen = () => {
  dataChannel.send("Hello World!");
};

dataChannel.onclose = () => {
  console.log("The Data Channel is Closed");
};

dataChannel 物件是從已建立的對等互連連線建立,您可以在信號發生前後建立。然後傳入標籤,將這個管道與其他管道區分開來,以及一組選用設定:

const dataChannelOptions = {
  ordered: false, // do not guarantee order
  maxPacketLifeTime: 3000, // in milliseconds
};

您也可以新增 maxRetransmits 選項 (失敗前嘗試的次數),但只能指定 maxRetransmits 或 maxPacketLifeTime,不能同時指定兩者。如要使用 UDP 語意,請將 maxRetransmits 設為 0,並將 ordered 設為 false。詳情請參閱下列 IETF RFC:Stream Control Transmission ProtocolStream Control Transmission Protocol Partial Reliability Extension

  • ordered:資料管道是否應保證順序
  • maxPacketLifeTime:嘗試重新傳送失敗訊息的最長時間
  • maxRetransmits:嘗試重新傳送失敗訊息的次數上限
  • protocol:允許使用子通訊協定,向應用程式提供中繼資訊
  • negotiated:如果設為 true,系統會移除其他對等互連裝置上的資料管道自動設定,讓您在另一端以相同 ID 建立資料管道
  • id:可為頻道提供專屬 ID,但只能與設為 truenegotiated 搭配使用)

一般人只需要使用前三個選項:orderedmaxPacketLifeTimemaxRetransmits。使用 SCTP (目前支援 WebRTC 的所有瀏覽器都使用這項通訊協定) 時,預設值為可靠且依序傳送。如果您想從應用程式層全面控管,使用不可靠且無序的傳輸方式是合理的做法,但在大多數情況下,部分可靠性就已足夠。

請注意,與 WebSocket 相同,RTCDataChannel 會在連線建立、關閉或發生錯誤時,以及收到來自其他對等互連裝置的訊息時,觸發事件。

這個挑戰安全嗎?

所有 WebRTC 元件都必須加密。使用 RTCDataChannel 時,所有資料都會透過資料包傳輸層安全標準 (DTLS) 加密。DTLS 是 SSL 的衍生版本,因此資料安全程度與使用任何標準 SSL 連線相同。DTLS 已標準化,並內建於所有支援 WebRTC 的瀏覽器。詳情請參閱 Wireshark 維基

改變對資料的看法

處理大量資料是 JavaScript 的痛點。Sharefest 的開發人員指出,這需要以新的方式思考資料。如果轉移的檔案大於可用記憶體容量,您必須考慮以新方式儲存這項資訊。這時,FileSystem API 等技術就能派上用場,詳情請見下文。

建構檔案共用應用程式

現在可以使用 RTCDataChannel 建立網頁應用程式,在瀏覽器中分享檔案。以 RTCDataChannel 為基礎表示轉移的檔案資料會經過加密,且不會觸及應用程式供應商的伺服器。這項功能加上可連線至多個用戶端以加快分享速度,讓 WebRTC 檔案分享成為網路的強大候選功能。

如要順利轉移,請按照下列步驟操作:

  1. 使用 File API 在 JavaScript 中讀取檔案。
  2. 使用 RTCPeerConnection 在用戶端之間建立對等互連連線。
  3. 使用 RTCDataChannel 在用戶端之間建立資料管道。

透過 RTCDataChannel 傳送檔案時,請注意下列幾點:

  • 檔案大小:如果檔案大小合理,且可儲存及載入為一個 Blob,您可以使用 File API 載入記憶體,然後透過可靠的管道傳送檔案 (但請注意,瀏覽器會限制傳輸大小上限)。檔案越大,處理起來就越棘手。如果需要分塊機制,系統會載入檔案塊並傳送至其他對等互連裝置,同時附上 chunkID 中繼資料,方便對方辨識。請注意,在這種情況下,您也需要先將區塊儲存至離線儲存空間 (例如使用 FileSystem API),並僅在擁有完整檔案時,才將檔案儲存至使用者的磁碟。
  • 區塊大小:這是應用程式的最小「原子」資料。由於目前有傳送大小限制 (但這會在日後的資料管道版本中修正),因此必須進行區塊化。目前建議的區塊大小上限為 64 KiB。

檔案完全轉移到另一端後,即可使用錨點標記下載:

function saveFile(blob) {
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = 'File Name';
  link.click();
};

PubShareGitHub 上的檔案共用應用程式都採用這項技術。兩者都是開放原始碼,可為以 RTCDataChannel 為基礎的檔案共用應用程式提供良好基礎。

那麼該怎麼做?

RTCDataChannel 開啟了新的大門,讓您以全新方式建構應用程式,用於檔案共用、多人遊戲和內容傳送。

  • 如先前所述,進行點對點檔案共用
  • 多人遊戲,搭配 WebGL 等其他技術,如 Mozilla 的 BananaBread 所示
  • PeerCDN 重新定義內容傳遞方式,這個架構透過對等互連資料通訊傳遞網路資產

改變應用程式建構方式

現在透過 RTCDataChannel 建立高效能、低延遲的連線,即可提供更引人入勝的應用程式。PeerJSPubNub WebRTC SDK 等架構可簡化 RTCDataChannel 的實作程序,且 API 現在已廣泛支援各種平台。

RTCDataChannel 的出現可能會改變您對瀏覽器資料傳輸的看法。

瞭解詳情