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

在兩個瀏覽器之間傳送資料以進行通訊、遊戲或檔案傳輸,可能會是一個相當複雜的程序。您必須設定及付費購買用於轉送資料的伺服器,並可能需要將這項服務擴展到多個資料中心。在這種情況下,可能會出現高延遲,且難以保護資料隱私。

您可以使用 WebRTC 的 RTCDataChannel API,直接從一個對等端轉移資料,藉此緩解這些問題。本文將說明如何設定及使用資料管道的基本概念,以及目前網路上常見的用途。

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

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

RTCDataChannel 則採用不同的做法:

  • 這項 API 可搭配 RTCPeerConnection API 使用,可啟用點對點連線功能。這麼做可縮短延遲時間,因為沒有中介伺服器,且「跳轉」次數也較少。
  • RTCDataChannel 使用 Stream Control Transmission Protocol (SCTP),可設定傳送語意-錯誤順序傳送和重新傳送設定。

RTCDataChannel 現已支援電腦版和 Android 版 Google Chrome、Opera 和 Firefox 的 SCTP。

警告:Signaling、STUN 和 TURN

WebRTC 可啟用點對點通訊,但仍需要伺服器進行信號傳送,以交換媒體和網路中繼資料,啟動點對點連線。

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

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

如要進一步瞭解 WebRTC 如何與伺服器搭配使用,以便進行信號傳送和網路連線,請參閱「實際應用中的 WebRTC:STUN、TURN 和信號傳送」。

功能

RTCDataChannel API 支援彈性的資料類型組合。這個 API 的設計目的是完全模擬 WebSocket,RTCDataChannel 支援 字串以及 JavaScript 中的部分二進位元類型,例如 BlobArrayBufferArrayBufferView。在檔案傳輸和多人遊戲時,這類類型會很有幫助。

RTCDataChannel 可在不可靠且無序的模式 (類似於 User Datagram Protocol 或 UDP)、可靠且有序的模式 (類似於 Transmission Control Protocol 或 TCP) 以及部分可靠模式中運作:

  • 可靠且有序的模式可確保訊息傳輸,以及訊息的傳送順序。這會產生額外的負擔,因此可能會讓這個模式的速度變慢。
  • 不穩定且無順序的模式無法保證每則訊息都能傳送至對方,也無法保證傳送順序。這麼做可減少額外負擔,讓這個模式的運作速度大幅提升。
  • 部分可靠模式可確保在特定情況下傳送訊息,例如重傳逾時或重傳次數上限。您也可以設定訊息的順序。

在沒有封包遺失的情況下,前兩種模式的效能大致相同。不過,在可靠且有序的模式中,遺失的封包會導致其他封包在後方阻斷,而遺失的封包在重新傳送並抵達時,可能已經過時。當然,您也可以在同一個應用程式中使用多個資料管道,每個管道都有自己的可靠或不可靠語義。

以下是 Ilya Grigorik 撰寫的「高效能瀏覽器網路連線」一文中,有用的表格:

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,但必須搭配將 negotiated 設為 true 才能使用

大多數人只需要使用前三個選項:orderedmaxPacketLifeTimemaxRetransmits。使用 SCTP (目前已被所有支援 WebRTC 的瀏覽器採用),可讓可靠且有序的預設值為 True。如果您想從應用程式層級完全控管,使用不可靠且無序的資料是合理的做法,但在大多數情況下,部分可靠的資料會更有幫助。

請注意,與 WebSocket 一樣,RTCDataChannel 會在建立、關閉或發生錯誤的連線時,以及收到來自其他端點的訊息時觸發事件。

這個挑戰安全嗎?

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

改變您對資料的看法

在 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 的出現,可能會改變您對瀏覽器資料傳輸方式的看法。

瞭解詳情