天天看點

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

作者:前端進階進階

大家好,很高興又見面了,我是"進階前端‬進階‬",由我帶着大家一起關注前端前沿、深入前端底層技術,大家一起進步,也歡迎大家關注、點贊、收藏、轉發!

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

進階前端‬進階

前言

在為您的應用程式選擇通信協定時,有很多不同的選擇。 本文将了解四種流行的解決方案:HTTP、WebSocket、gRPC 和 WebRTC。 我們将通過深入學習其背後原理、最佳用途及其優缺點來探索每個協定。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

通信方式在不斷改進:變得更快、更友善、更可靠,從使用信鴿發送資訊,發展到郵政郵件,再到固定電話的發明,再到便攜式移動裝置。未來,甚至可能将會議和生日派對過渡到 VR(但願這隻是個玩笑!)。

當然,最好的溝通方式總是要視情況而定。快速的短信有時比長的電子郵件更好。 其他時候,與團隊進行視訊通話是交流資訊的最佳方式, 相比之下,重要的保險檔案必須通過普通郵件發送并以紙質形式傳遞。而使用的網絡技術和協定也是如此,不同的應用程式有不同的通信需求。

1.概述

在本文中,我們将介紹一些可以作為開發人員使用的流行通信協定,并探讨不同協定的優缺點。 正如開頭所說,沒有比另一個更好的解決方案,隻有一些解決方案更适合特定的應用程式或問題。

一些應用程式需要點對點連接配接,具有低延遲和高資料傳輸,并且可以接受一些資料包(資訊)丢失。 有些應用程式可以根據需要輪詢伺服器,而不需要擷取被‬輪詢方的同等資料,有些應用程式需要具有資料可靠性的實時通信,諸如此類。

線上多人遊戲、消息傳遞應用程式、部落格網站、媒體庫應用程式和視訊會議軟體都有不同的通信和資料需求。如果您正在建構視訊流解決方案,那可能‬還有其他注意事項。

2.什麼是通信協定?

在計算機網絡中,協定是一組規則,用于管理資料在裝置之間的交換方式。 該協定定義了通信的規則、文法、語義和同步以及可能的錯誤恢複方法。本文中讨論的協定定義了應用層軟體如何互相互動。 不同的協定遵循不同的規則,了解每個協定的優勢和局限性至關重要。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

在本文中,您将了解以下協定:

  • HTTP(超文本傳輸協定):是分布式協作和超媒體資訊系統的應用協定。 HTTP 是網際網路資料通信的基礎, 超文本是在包含文本的節點之間使用邏輯連結(超連結)的結構化文本。 HTTP 是交換或傳輸超文本的協定。
  • HTTP/2: 旨在解決原始 HTTP 協定的缺點并提高性能。 HTTP/2 比 HTTP/1.1 更快、更高效,它支援多路複用,允許多個請求和響應在單個連接配接上進行多路複用。 其他值得注意的功能包括标頭壓縮和伺服器推送, 它正逐漸成為網絡流量的預設協定。
  • WebSocket: 是一種允許用戶端和伺服器之間進行雙向通信的協定。 它是處理實時資料應用程式的熱門選擇,例如聊天應用程式、線上遊戲和實時資料流。
  • gRPC :是一個使用 HTTP/2 進行傳輸的現代開源 RPC 架構。 對于需要進行大量小而快的 API 調用的應用程式來說,這是一個很好的選擇。 gRPC 為多種語言生成跨平台的用戶端和伺服器綁定,使用戶端應用程式可以直接調用不同機器上的伺服器應用程式的方法,就好像它是本地方法‬一樣。
  • WebRTC: 是一種允許用戶端之間進行實時通信,并使得建立直接對等連接配接成為可能的技術。 它用于視訊、聊天、檔案共享和實時視訊流應用程式。

3.了解 TCP 和 UDP

在深入研究上述應用層之前,重要的是要對 TCP 和 UDP 有一個基本的了解,這兩個底層傳輸層以根本不同的方式促進資料傳輸。

  • TCP(傳輸控制協定):是定義如何通過 Internet 建立和維護網絡對話的标準。 TCP 是 Internet 和任何面向連接配接的網絡上最常用的協定。 當您浏覽網頁時,您的計算機會向網絡伺服器發送 TCP 資料包。 Web 伺服器通過将 TCP 資料包發送回您的計算機來響應。 在交換任何資料之前,首先在兩個裝置之間建立連接配接,并且 TCP 使用糾錯來確定所有資料包都成功傳遞。 如果資料包丢失或損壞,TCP 将嘗試重新發送它。
  • UDP(使用者資料報協定):是一種無連接配接、不可靠的傳輸層協定。 它不需要建立或維護連接配接,也不保證消息将按順序傳遞。 這意味着如果資料包未發送或損壞,可能會丢失一些資料。 UDP 通常用于流媒體或實時應用程式,在這些應用程式中,丢失資料包的問題比確定傳遞要少。

4.HTTP/1

對應用層所有基于網際網路的通信和資料傳輸的基礎——HTTP(超文本傳輸協定)有一個基本的了解是很重要的。在更詳細地探索其他協定并充分了解它們提供的功能之前,了解 HTTP/1 及其局限性也很重要。

使用 HTTP,用戶端和伺服器通過交換單獨的消息進行通信。 用戶端發送的消息稱為請求,伺服器發送的消息稱為響應。 這些消息作為正常文本消息通過 TCP 連接配接發送。 它們也可以使用 TLS 加密并使用 HTTPS 協定發送。

用戶端通常是在使用者手機或計算機上運作的 Web 浏覽器或應用程式,但從技術上講,它可以是任何東西,例如,抓取網站的腳本。HTTP 請求隻能沿一個方向流動,即從用戶端到伺服器。 伺服器無法發起與用戶端的通信, 它隻能響應請求。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

HTTP 非常适合傳統的 Web 和用戶端應用程式,在這些應用程式中,資訊是按需擷取的。 例如,你重新整理了一個頁面,向伺服器發出了擷取最新資訊的請求。

在接下來的部分中,我們将探讨 HTTP/1 的一些限制。

4.1.HTTP/1 實時傳輸

當消息需要從用戶端實時發送到伺服器時,HTTP/1 效率低下。 例如,如果伺服器上有新資訊需要與用戶端共享,則此事務隻能在用戶端發起請求後發生。當然,也有一些解決方法,例如‬使用稱為 HTTP 短輪詢和長輪詢以及伺服器發送事件的技術。

4.1.1 短輪詢

HTTP 短輪詢是一種用戶端重複向伺服器發送請求直到它響應新資料的技術。 一旦它接收到資料,它就會再次啟動該過程并反複詢問,直到有其他可用的資料‬為止。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

這是一種低效的實時通信政策,因為它通過持續傳輸和解析 HTTP 請求/響應浪費了大量資源。

4.1.2 長輪詢

使用 HTTP 長輪詢,從用戶端發出單個請求,然後伺服器保持該連接配接打開,直到有新資料可用并且可以發送響應。 用戶端收到響應後,立即再次建立新的連接配接。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

長輪詢比短輪詢更有效,但不是實時通信的最佳解決方案。

4.1.3 伺服器發送的事件 (SSE)

伺服器發送的事件允許用戶端保持打開的連接配接并實時從伺服器接收推送消息,而不必不斷地輪詢伺服器以擷取新資料。 這是一種單向連接配接,是以您無法将事件從用戶端發送到伺服器。

SSE 是一種标準,描述了一旦建立了初始用戶端連接配接,伺服器如何啟動向用戶端的資料傳輸。

4.2 HTTP/1 的性能問題

大多數 HTTP 資料流由小的、密集‬的資料傳輸組成,而 TCP 針對長期連接配接和批量資料傳輸進行了優化。 在大多數情況下,網絡往返時間是 TCP 吞吐量和性能的限制因素。 是以,延遲是性能瓶頸,大多數 Web 應用程式都可以克服它。

上面的意思是 HTTP 使用的 TCP 是為處理長期連接配接和傳輸大量資料而建構的。 另一方面,HTTP/1 會打開一堆短暫的 TCP 連接配接,并且通常隻發送小塊資料。

4.2.1 隊首阻塞

HTTP/1.0 的一個性能問題是您必須為每個請求/響應打開一個新的 TCP 連接配接。 對于 HTTP 最初發明的目的而言(擷取超文本文檔),這不是問題。 文檔部分很重要,因為 HTTP 并不意味着“超媒體”。

随着網絡的發展,為每個請求打開一個新的 TCP 連接配接成為一個問題。 我們開始建構完整的應用程式而不是簡單的網頁,浏覽器需要檢索的媒體和檔案的數量變得更多。 設想一個典型的 Web 應用程式需要 HTML、CSS 和 JavaScript 檔案,以及各種圖像和其他資産。 對于每個檔案,都必須建立一個新的連接配接。

随之而來的是 HTTP/1.1,它具有持久連接配接,它定義了可以在同一個 TCP 連接配接上有多個請求或響應。這個解決方案絕對是一個改進,但它不允許伺服器同時傳回多個響應。 這是一個序列化協定,您必須在其中發送請求并等待響應,然後發送第二個請求,依此類推。 這稱為隊頭阻塞。

然而,實作某種并行性是可能的,因為浏覽器最多可以打開六個(不同浏覽器有差異)同一來源的 TCP 連接配接(其中“來源”被定義為主機和端口号的唯一組合)。

例如,如果您有一個需要加載 12 張圖像的照片庫應用程式,那麼将發出六個請求來加載前六張圖像,并且每個請求都會在背景打開一個新的 TCP 連接配接。 其他六個圖像将被阻止,直到收到響應并且打開的連接配接之一可用于加載下一個圖像。 最初的六個開放的同源 TCP 連接配接将在可用時被重用,但您僅限于六個活動連接配接。

很自然地,程式員找到了一個簡單的解決方法——改變圖檔源。 不是在同一個源上托管所有資産,而是在一個源上托管六個圖像,其餘的在另一個源上。 現在您可以有 12 個并發請求(或打開 TCP 連接配接),這被稱為“分片”。

  • 圖檔 1–6 托管在 1.images.com 上
  • 圖檔 7–12 托管在 2.images.com 上

但是,您可以執行此操作的次數是有限制的,而且很難确定最佳的分片數量。 在某些時候,添加更多分片會增加複雜性、增加開銷,并可能導緻鍊路擁塞和資料包丢失。

還有其他問題,因為每個 TCP 連接配接都會給伺服器增加不必要的開銷。 連接配接互相競争,每次 TCP 和 TLS 握手都會增加不必要的成本,并且必須使用其他伺服器/代理資源來維持活動連接配接。 HTTP/1 使用底層 TCP 連接配接的方式有一個明顯的限制。

4.2.2 标頭(Headers)和 Cookie 爆炸

另一個問題是,随着 HTTP 規範的發展,規範中添加了更多的标頭。 開發人員還可以選擇将 cookie 添加到标頭,這些 cookie 可以任意大。 這增加了很多大小,因為每個請求和響應都需要傳輸所有這些文本資訊,并且 HTTP/1.1 不包含壓縮标頭和中繼資料的機制。

如果您需要一個高性能的 RPC 協定,這種開銷會變得更大,此時 HTTP 不再是最佳解決方案。

4.2.3 優先級(Prioritization)

在 HTTP/1.1 中,浏覽器通過在用戶端持有一個優先級隊列來“确定”資源的優先級,并對如何充分利用可用的 TCP 連接配接進行有根據的猜測。 浏覽器嵌入了啟發式方法,用于确定哪些資源比其他資源更有價值。

例如,加載 CSS 将比加載圖像具有更高的優先級。問題在于,作為開發人員,您無法确定一個請求的優先級高于另一個請求或更改正在進行的消息的優先級。 首先加載什麼内容取決于浏覽器,您對優先級方案沒有發言權。

5.HTTP/2

5.1 HTTP/2 的優點

HTTP/2 是 HTTP 協定的改進版本,解決了上述 HTTP/1 的所有性能問題,并在不改變任何語義(标頭等)的情況下添加了其他增強功能。

HTTP/2 中最顯着的變化是使用多路複用。通過單個 TCP 連接配接同時發送和接收多個 HTTP 請求和響應。 所有 HTTP/2 連接配接都是持久的,每個源隻需要一個連接配接。 這允許更有效地使用網絡資源,并可以顯着提高應用程式的性能。

HTTP/2 的其他一些好處:

  • 使用标頭壓縮來減小标頭的大小,進而避免一遍又一遍地發送相同的純文字标頭。 這顯着減少了請求/響應的開銷和發送的資料量。
  • 啟用優先級,允許用戶端(開發人員)指定其所需資源的優先級。 也可以更新正在進行的請求的優先級——例如,在滾動時,如果圖像不再可見,則優先級可以改變。
  • 使用伺服器推送,在用戶端請求之前将資料發送到用戶端。 這可用于通過消除用戶端發出多個請求的需要來縮短加載時間。

5.2 HTTP/2 是如何工作的?

HTTP/2 中的基本協定單元是幀。 這種新的二進制幀機制改變了用戶端和伺服器之間的資料交換方式。

該标準定義了十種不同的幀類型,每種都有不同的用途。 例如,HEADERS 和 DATA 幀構成了 HTTP 請求和響應的基礎:

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

幀是承載特定類型資料的最小通信機關。 其他一些幀示例是:

  • 設定(SETTINGS):在開始或連接配接期間交換設定資訊。
  • 優先級(PRIORITY):重新配置設定消息的優先級。
  • PUSH_PROMISE:允許伺服器向您推送資料,這是對伺服器将發送的内容的承諾。 例如,如果您請求 index.html,伺服器可以建立一個 PUSH_PROMISE 來承諾推送 app.js 和 styles.css,這意味着用戶端不需要主動請求這些資源。

幀組合在一起形成消息,例如上圖中的标題和資料幀。 這等同于正常的請求或響應。最後,一系列消息可以成為流的一部分。 這允許用戶端和伺服器之間的雙向資料流以及完整的請求和響應多路複用。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

上圖有點誤導,給人的印象是用戶端和伺服器之間打開了多個連接配接。但它是單個 TCP 連接配接,資料以非阻塞方式在用戶端和伺服器之間自由流動。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

新的二進制架構層允許用戶端和伺服器将 HTTP 消息分解為獨立的幀,組合發送,然後在另一端重新組合它們。這隻是 HTTP/2.0 工作原理的總結。 如果您想了解更多資訊并探索優先級排序、伺服器推送和标頭壓縮,請參閱文末資料。

5.3 HTTP/2 雙向資料流

HTTP/2 規範表明:

“流”是在 HTTP/2 連接配接中用戶端和伺服器之間交換的獨立地、雙向幀序列。           

流有幾個重要的特征:

  • 單個 HTTP/2 連接配接可以包含多個并發打開的流,其中任一端點交錯來自多個流的幀。
  • 流可以單方面建立和使用,也可以由用戶端或伺服器共享。
  • 流可以被任一端點關閉。

伺服器推送功能存在很多誤解,它允許伺服器通過 HTTP/2 主動發送它認為您可能需要的資源,例如 .js 和 .css 檔案,而無需用戶端請求。 這與雙向流無關,隻是一種針對可緩存資源的 Web 優化技術。

事實是,對于 HTTP/2 伺服器無法啟動流。 但是一旦用戶端通過發送請求打開一個流,雙方就可以随時通過持久套接字發送資料幀。 一個很好的例子是 gRPC,我們将在後面讨論。

使用 HTTP/2,可以實作雙向資料流,你可以争辯說它是比 WebSockets 之類的東西更優化的解決方案,或者你可以争辯說它不是。 我們将在 WebSocket 部分更詳細地讨論這個問題。

6.WebSockets

6.1 WebSockets 規範說明

來自 WebSocket 協定規範:

該技術的目标是為基于浏覽器的應用程式提供一種機制,這些應用程式需要與不依賴于打開多個 HTTP 連接配接的伺服器進行雙向通信(例如,使用 XMLHttpRequest 或 iframe 和長輪詢)。           

WebSockets 的發明是為了實作用戶端和伺服器之間的全雙工通信,這允許資料立即通過單個打開的連接配接雙向傳輸。

建立 WebSocket 連接配接後,用戶端無需輪詢伺服器以擷取更新。 相反,通信是雙向發生的。 與 HTTP/1 的原始長輪詢和短輪詢相比,這提高了速度和實時能力。 WebSocket 沒有特定要遵循的資料格式, 您可以使用它發送任何資料、文本或位元組,這種靈活性是 WebSockets 流行的原因之一。

其中一些内容聽起來可能與我們在 HTTP/2 部分中讨論的内容很熟悉,但重要的是要注意 WebSockets 是在 HTTP/2 之前很久就發明的。 稍後我們将對它們進行更多比較。

6.2 WebSockets 如何工作?

WebSockets 底層基于 TCP 的傳輸層運作。 要建立 WebSocket 連接配接,用戶端和伺服器首先需要通過正常的 HTTP/1.1 連接配接執行握手。此握手是從 HTTP 更新到 WebSockets 的橋梁。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

下面是一個示例用戶端握手請求。用戶端可以使用稱為更新标頭的 HTTP/1.1 機制将其連接配接從 HTTP 切換到 WebSockets:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13           

然後伺服器将用一個特殊的響應結束握手,該響應表明協定将從 HTTP 更改為 WebSocket:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=           

WebSockets 需要具有 ws:// 或 wss:// 方案的統一資源辨別符 (URI)。 ws:// 方案用于未加密連接配接,wss:// 方案用于加密連接配接,類似于 HTTP URL 使用 http:// 或 https:// 方案的方式。

一旦建立了雙向通信通道,用戶端和伺服器就可以來回發送消息。 這些消息可以是從二進制資料到文本的任何内容。 WebSocket 連接配接将保持打開狀态,直到用戶端或伺服器斷開連接配接。

6.3 WebSocket 多路複用

在撰寫本文時,WebSocket 協定不支援内置多路複用。 我們在 HTTP/2 部分讨論了多路複用,了解到它是 HTTP/2 的内置功能,并且可以在同一連接配接上多路複用多個流。 每個流都有一個唯一的辨別符,所有發送的幀都有一個與相應流關聯的 ID。

不支援多路複用意味着 WebSocket 協定需要為每個 WebSocket 連接配接建立一個新的傳輸連接配接。 例如,在同一浏覽器的不同頁籤中運作的多個用戶端将使用單獨的連接配接。 要在 WebSockets 上進行多路複用,您通常需要依賴第三方插件或庫。

6.4 WebSocket 與 HTTP/2

HTTP/2 取代了 WebSockets 了嗎? 答案是不!

HTTP/2 使雙向流成為可能,這使得 WebSockets 不是唯一/最佳選擇。 與 WebSockets 相比,HTTP/2 作為規範為您做了更多的工作。 它具有内置的多路複用功能,在大多數情況下,将導緻與源站建立的 TCP 連接配接更少。 另一方面,WebSockets 提供了很大的自由度,并且在建立連接配接後如何在用戶端和伺服器之間發送資料方面沒有限制。 但是,您需要自己管理重新連接配接(或依賴為您執行此操作的庫)。

至于那個更好,本文不給出答案,每個人有每個人的看法。WebSockets 提供了很大的靈活性,并且作為一個既定标準,它得到所有現代浏覽器的完全支援,并且圍繞用戶端和伺服器庫的生态系統是強大的。有關更詳細和自以為是的讨論,請參閱這些 Stack Overflow 問題:

  • HTTP/2 是否讓 WebSocket 過時了
  • 用于低延遲用戶端到伺服器消息的 HTTP/2 或 Websockets
  • 用于雙向消息流的 HTTP/2 與網絡套接字

還有一個 RFC 允許在 HTTP/2 連接配接的單個流上運作 WebSocket 協定的機制。能夠從 HTTP/2 引導 WebSockets ,即允許兩個協定共享一個 TCP 連接配接,并将 HTTP/2 對網絡的更有效使用擴充到 WebSockets。這已在 Chrome 和 Firefox 中實作。 您可以在此處閱讀 Chrome 設計文檔和動機。

6.5 什麼時候使用 WebSocket?

Websockets 最适合需要實時雙向通信的應用程式,以及需要快速傳輸小塊資料的應用程式:

  • 聊天應用
  • 多人遊戲
  • 協作編輯應用程式
  • 直播體育賽事
  • 股票交易應用
  • 實時活動提要

對于伺服器發送事件 (SSE), 在 HTTP/2 上非常高效且易于使用。 SSE 不是雙向通信系統; 伺服器單方面向用戶端推送資料。 但是,如果您所需要的隻是伺服器向用戶端發送資料的一種方式,那麼這可能是比使用 WebSockets 更好的選擇。 當 HTTP/2 不可用時,SSE 也會回退到 HTTP/1.1。 此外,用戶端(或浏覽器)為您管理連接配接并支援自動重新連接配接。

如果通過 WebSockets 的連接配接丢失,則不包含用于負載平衡或重新連接配接的機制。 這必須手動或由第三方庫實作。

6.gRPC

gRPC 是一個現代開源高性能遠端過程調用 (RPC) 架構,可以在任何環境中運作。 它可以通過對負載平衡、跟蹤、健康檢查和身份驗證的可插拔支援,有效地連接配接資料中心内和跨資料中心的服務。 它還适用于分布式計算的最後一英裡,将裝置、移動應用程式和浏覽器連接配接到後端服務。

gRPC 是一個開源的、基于約定的 RPC 系統,最初由谷歌開發。 gRPC 使應用程式能夠透明地通信并簡化連接配接系統的建構。它為多種語言生成跨平台的用戶端和伺服器綁定,使用戶端應用程式可以直接調用不同機器上伺服器應用程式的方法,就好像它是本地對象一樣。

gRPC 基于 HTTP/2 建構,利用雙向流和内置傳輸層安全性 (TLS) 等功能。

6.1 gRPC 動機

深入了解 gRPC 背後的動機、發明它的原因以了解其好處非常重要。 為什麼不使用我們已經擁有的現有技術:例如 HTTP/2 和 WebSockets? 為什麼我們需要在已有的能力之上再抽象一層?

可以通過多種方式建構資料并通過 Internet 發送資料。 一些流行的例子是 SOAP、REST 和 GraphQL。 您甚至可以建立自己的協定,通過原始 TCP 發送資料,并根據需要自行處理實作。

但無論您選擇什麼作為您的通信協定,問題在于您需要確定用戶端和伺服器就該協定達成一緻。 例如,如果您正在建構 REST API,則需要用于發送 REST 資料的用戶端庫是 HTTP 庫。 HTTP 庫預設内置于浏覽器中,浏覽器會為您處理一切:

  • 它與伺服器建立通信。
  • 它處理 HTTP/2 并回退到 HTTP/1, 并且将來需要支援 HTTP/3。
  • 它處理 TLS 并協商協定。
  • 它處理标頭、流和其他所有内容。

但是,如果您不在浏覽器上怎麼辦? 如果您是在某個伺服器上運作的 Python 應用程式、GoLang CLI 或在 iOS 上運作的 Flutter 應用程式怎麼辦? 所有這些用戶端都需要自己的 HTTP 庫,該庫可以了解您正在與之通信的協定。

幸運的是,許多人正在為所有這些語言和架構開發各種 HTTP 庫。 有些語言甚至有多個具有不同特性的 HTTP 庫。 然而,所有這一切都是有代價的,那就是維護。

如果您要将伺服器更新到 HTTP/2(如果您使用的 GoLang 庫支援它),此成本可能會影響您。 但是,在您的前端 Python 用戶端上,等效的 HTTP 庫尚未實作 HTTP/2,或者可能不再維護。

随着 HTTP 規範的發展,這些庫必須同步更新,如安全問題、新功能等。 HTTP 隻是一個例子,對于 WebSocket 協定或任何其他協定也是如此。 有些東西可能在主流浏覽器中得到很好的實作,但該功能必須移植到多種不同的語言和架構中。

6.2 gRPC 有何不同?

gRPC 試圖通過維護流行語言本身的庫來解決這個問題,這意味着所有這些語言都将支援添加的新功能。

gRPC 使用 HTTP/2 作為其協定,但是,這個實作對您是無感的。 将來,gRPC 的維護者可以輕松地将 HTTP/2 替換為 HTTP/3,您将立即從該更改中受益。

gRPC 還使用協定緩沖區作為接口定義語言 (IDL) 及其底層消息交換格式。 這種格式是語言中立的,可以輕松地在不同的程式設計語言之間進行通信。 我們将在下一節中更多地探讨這個概念。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

6.3 什麼是協定緩沖區?

Protocol buffers 是 Google 設計的語言中立、平台中立、可擴充的結構化資料序列化機制——想想 XML,但更小、更快、更簡單。 您一次性定義了資料的結構方式。 然後,您可以使用特殊生成的源代碼輕松地将結構化資料寫入各種資料流并使用各種語言從中讀取結構化資料。

在 API 機制的設定中,您通常無需關心協定本身。 例如,如果您使用的是 REST,您通常隻是發送帶有鍵/值對的 JSON 消息,直到消息到達接收端才進行檢查。 此消息通常可以是任何内容,由您來確定定義了正确的結構。

檢視以下 JSON 資料(payload):

{
'id': 123,
'name': 'Gordon',
'email': '[email protected]'
}           

在用戶端/伺服器上接收到此資料,就可以将其反序列化為一個對象,例如:

class Person {
    int id;
    String name;
    String email
}           

但是,作為開發人員,您需要為上述資料實作正确的序列化和反序列化邏輯——這可能涉及手動編寫 toJson 和 fromJson 方法,可以依賴于代碼生成,或者它可能是你正在使用的語言。

無論您如何序列化此資料,底層代碼都需要手動更新,可能在多個環境中,以防模式發生變化。而使用協定緩沖區,您可以建立一個模式來定義字段的對象類型并指定哪些是必需的,哪些是可選的:

// The request message containing the person’s information
Message Person {
    optional int32 id = 1;
    required string name = 2;
    optional string email = 3;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}           

然後您可以指定對外的方法:

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (Person) returns (HelloReply) {}
}           

一旦您指定了資料結構和模式,您就可以使用協定緩沖區編譯器 将 protoc 從您的 proto 定義中,以您的首選語言生成資料通路類。這些是描述 proto 檔案中概述對象的接口,每個字段都有通路器,以及将整個結構序列化/解析為原始位元組的方法。

6.4 gRPC 模式

gRPC 有四種傳輸方式, 這四種模式實作了之前讨論的行為,例如,正常的請求/響應、SSE 和 WebSockets。

6.4.1 一進制 RPC

一進制 RPC 是簡單的請求和響應,類似于調用函數。 用戶端請求一些資料,伺服器進行一些處理并傳回該資料。

6.4.2 伺服器流式 RPC

伺服器流式 RPC,其中用戶端向伺服器發送單個請求并期望多個響應或響應流。 用戶端從傳回的流中讀取,直到沒有更多消息為止。

一個例子是視訊流,您請求加載視訊,伺服器響應視訊流。

6.4.3 用戶端流式 RPC

用戶端流式 RPC,其中用戶端寫入一系列消息并将它們發送到伺服器,再次使用提供的流。 用戶端完成消息寫入後,它會等待伺服器讀取消息并傳回響應。

一個例子是将一個大檔案上傳到伺服器,一旦所有資料發送完畢,用戶端可以發送最終消息以訓示上傳完成,并且伺服器可以選擇響應。

6.4.4 雙向流 RPC

用戶端和伺服器流媒體的組合。 聊天應用程式或多人視訊遊戲是資料需要在用戶端和伺服器之間自由流動的示例。

雙向流式 RPC,雙方使用讀寫流發送一系列消息。 這兩個流獨立運作,是以用戶端和伺服器可以按照他們喜歡的任何順序進行讀寫。

在雙向流式 RPC 中,調用由調用方法的用戶端發起。 用戶端和伺服器端流處理是特定于應用程式的。 由于兩個流是獨立的,是以用戶端和伺服器可以按任意順序讀寫消息。

6.5 微服務

gRPC 強大之處的一個很好的例子是在微服務中。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

在這個例子中,我們有用 Python、Java 和 GoLang 編寫的微服務,需要在它們之間發送資料。

使用 HTTP/1.1 和 JSON 将需要您為每種語言實作 HTTP 連接配接和序列化。 您還需要確定為每種語言正确實施架構,如果 API 發生變化,則需要手動更新所有服務。

另一方面,gRPC 為我們處理了 HTTP/2.0 協定的實作。 編寫單個模式,可以為所有使用的語言生成相應的代碼。 這種模式可以看作是所有語言都需要遵守的契約,這使這些服務之間的通信更加容易和可靠。

6.6 gRPC 性能

gRPC 速度很快,通常比 REST 等價物的性能高得多:

  • 協定緩沖區被序列化并作為二進制檔案通過網絡發送,這比普通的 JSON 消息小得多。
  • gRPC 使用 HTTP/2.0 進一步改進

gRPC 有效壓縮發送的資料具有顯著優勢,因為傳輸的資料負載越小,需要的 TCP 往返次數就越少。 最大傳輸單元 (MTU) 是表示聯網裝置将接受的最大資料包的大小,即 1,500 位元組。

壓縮是自動處理的,你隻需使用 gRPC 就可以從中受益。 作為替代方案,可以在通過正常 HTTP 發送之前使用 GZIP 之類的東西來壓縮 JSON 消息。 然而,這可能會帶來不便,并增加了一層複雜性。 不同的語言和環境也可能對 GZIP 和其他等效壓縮工具有不同級别的支援。 對于您使用的每種語言,您都需要自己重新實作正确的壓縮和通信邏輯。 這與我們讨論的有關 HTTP 庫的問題類似。

6.7 什麼時候應該使用 gRPC?

如果您使用多種不同的程式設計語言,這些語言需要彼此緊密內建,并且需要快速頻繁地發送大量資料的通信,那麼 gRPC 将是完美的選擇。

  • 優點:
    • 使用 gRPC 流式傳輸,可以輕松确定上傳/下載下傳進度,無需發出任何不必要的更新請求。
    • 可以取消請求。
    • HTTP/2 的所有優點。
    • 如果 gRPC 支援你的語言,你就不必引入外部庫。
  • 缺點:
    • gRPC 不支援所有語言。
    • 該架構可能會讓人感到限制和麻煩。
    • 與 WebSockets 相比,它的設定可能很複雜。
    • 出現時間較晚,錯誤可能難以調試。
    • 與 gRPC 的通信本身并不适用于 Web 浏覽器, 您需要使用 gRPC-Web 庫。

7.WebRTC

7.1 WebRTC 特點

WebRTC 是一個免費的開源項目,可為基于開放标準運作的應用程式提供實時通信 (RTC) 功能。 它支援在對等點之間發送視訊、語音和通用資料。

該技術作為一組适用于所有主流浏覽器的 JavaScript API 和适用于 Android 和 iOS 應用程式等本機用戶端的庫提供。

WebRTC根本上不同于 WebSockets 和 gRPC,一旦建立連接配接,資料就可以(在某些情況下)直接在浏覽器和裝置之間實時傳輸,而無需接觸伺服器。           

這減少了延遲并使 WebRTC 非常适合音頻、視訊或螢幕共享,低延遲并且可發送大量資料。

7.2 WebRTC 動機

WebRTC 旨在标準化媒體(例如音頻和視訊)如何通過線路進行通信,并通過簡單易用的 API 友善地實作這一目标。

其他解決方案,例如 WebSockets,确實可以在兩個對等點之間傳輸任何資料; 但是,此資料需要通過代理或伺服器傳輸。 依賴另一台伺服器會增加延遲,因為通過它發送的所有内容都需要接收、處理和解密。對于視訊流甚至實時聊天,這種延遲是不可取的。

現在的浏覽器也比幾年前更強大。 浏覽器可以通路網絡攝像頭和麥克風,需要内置 API 和一種簡單的方法來傳輸這些豐富的資訊。 WebRTC 旨在簡化整個過程,并公開浏覽器本機可用的,易于使用的 API。

7.3 WebRTC 問題

動機已經明确,WebRTC 似乎是一種神奇的解決方案,可以讓兩個對等方之間的通信更快。 但不幸的是,存在一些問題。

  • 第一個問題是建立點對點連接配接并不簡單,網際網路很複雜。加利福尼亞的 Alice 和南非的 Ben 之間有很多路由器、代理和防火牆。 在某些情況下,可能無法在兩個對等點之間建立直線。 兩個對等點之間的連接配接可能需要繞過阻止打開連接配接的防火牆,您可能沒有公共 IP 位址,或者路由器可能不允許對等點之間的直接連接配接。
  • 第二個問題是需要有一種方法讓兩個對等點互相發現并确定可以進行通信的最佳路由。 這需要在兩個用戶端知道如何最好地互相通信之前在兩個用戶端之間共享某些資訊,而共享此資訊的一種常見方法是使用 WebSockets。

這有點好笑, 一個 HTTP 連接配接更新為 WebSocket 連接配接隻是為了共享建立 WebRTC 連接配接的資訊。

如果您真的想了解 WebRTC 的功能及其複雜性,您需要熟悉一些可能不熟悉的術語:NAT、STUN、TURN、ICE、SDP 和信令。

7.4 WebRTC 是如何工作的?

在上面的概述中,我們描述了 WebRTC 的動機,本節将深入探讨您需要了解的一些底層概念,以充分掌握 WebRTC。

7.4.1 網絡位址轉換 (NAT)

了解 NAT 是什麼以及它如何工作對于了解 WebRTC 至關重要。NAT 用于為您的裝置(筆記本電腦或手機)提供公共 IP 位址; 這很重要,因為我們要在可能都在路由器後面的兩個對等點之間建立連接配接。 路由器将有一個公共 IP 位址,連接配接到路由器的每個裝置都将有一個私有 IP 位址。

這些裝置不直接暴露在網際網路上。 相反,所有流量都通過與外界通信的路由器。 當您從遠端伺服器請求資源時,路由器負責将請求從本地計算機“路由”到該伺服器,并将伺服器的響應路由回本地計算機。

這些請求從裝置的私有 IP 位址轉換為具有唯一端口的路由器的公共 IP,然後存儲在 NAT 表中。 這樣,本地網絡上的每個裝置都沒有必要擁有唯一的公共 IP。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

上圖是 NAT 表的簡單示例。 假設私有 IP 為 192.168.1.50 的本地裝置請求公共位址 82.88.31.26:80 擷取一些資料。

這是通過本地裝置首先向路由器發送請求,路由器将請求路由到遠端裝置來實作的。 路由器然後告訴遠端裝置将響應發送到其外部 IP 位址,具有唯一端口,在本例中為 86.88.71.25:8830。

這個唯一的端口很重要,因為它将允許路由器确定送出請求的本地裝置。 所有這些資訊都存儲在 NAT 表中, 一旦路由器得到響應,它就可以執行查找并決定将響應轉發到哪個本地裝置。

當我們有一個正常的請求/響應對,即一個裝置和一個伺服器時,這很容易了解。 但是,如果另一個具有完全不同 IP 位址的外部裝置決定将資料包發送到先前使用的同一端口上的路由器外部 IP 位址,會發生什麼情況? 路由器是否應該将其轉發到映射到該端口号的本地裝置?

該決定取決于路由器使用哪種 NAT 轉換,并最終确定是否可以建立對等連接配接。 根據您使用的路由器,它會執行不同的 NAT 轉換。 有四種不同的 NAT 轉換方法:

  • 一對一 NAT
  • 将一個外部 IP 位址和端口(通常是公共的)映射到一個内部 IP 位址和端口(通常是私有的)。 在上面的示例中,如果路由器在端口 8830 和外部 IP 86.88.71.25 上收到響應,它會将其轉發到本地裝置 192.168.1.50,因為這是送出請求的本地裝置(從 NAT 表中檢索的資訊 ). 路由器不關心目标 IP 或響應的來源。 如果它在特定的外部端口上,它将轉到該本地裝置。
  • 位址限制 NAT
  • 僅當本地裝置先前已将資料包發送到遠端 IP 位址時,遠端裝置才能将資料包發送到本地裝置。 總之,我們隻有在之前與該主機通信過的情況下才允許它。 在上面的例子中,隻允許來自 86.88.71.25 的資料包
  • 端口限制 NAT
  • 與位址限制 NAT 相同,但限制還包括端口号。 如果内部裝置先前已将資料包發送到 IP 位址 X 和端口 P,則遠端裝置隻能将資料包發送到内部裝置。在上面的示例中,僅允許來自 86.88.71.25 和端口 80。
  • 對稱 NAT
  • 限制最嚴。 為此,外部 IP、外部端口、目标 IP 和目标端口都必須與 NAT 表中的内容相比對。 這意味着資料包隻能發送到本地裝置的特定端口,前提是該裝置是請求目标 IP 和端口的裝置。

WebRTC 不能在對稱 NAT 上工作,要了解為什麼我們需要了解什麼是 STUN 伺服器。

7.4.2 NAT 的會話周遊實用程式 (STUN)

STUN 是一種協定,可通過 NAT 告訴您您的公共 IP 位址/端口,并确定您的路由器中會阻止與對等方直接連接配接的任何限制。 STUN 伺服器是一種機制,供用戶端發現 NAT 的存在以及 NAT 的類型,并确定 NAT 的外部 IP 位址和端口映射。

一個 STUN 請求的目的是确定你的公開存在,這樣這個公開存在就可以與其他人交流,就可以與你聯系——這種交流被稱為信号,我們将在後面詳細讨論。

它适用于一對一、位址受限和端口受限的 NAT。 但不适用于對稱 NAT。 因為當您向 STUN 伺服器請求您的公共資訊時,該通信對是專門為送出請求的用戶端建立的。 使用對稱 NAT 不可能涉及另一個對等點——通過本地裝置端口的通信僅限于 STUN 伺服器。

STUN 伺服器重量輕,維護成本低。 有公共的 STUN 伺服器可以免費查詢。

下圖說明了 STUN 何時工作以及何時可以建立對等連接配接。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

另一方面,如果無法建立點對點連接配接,例如,當對等點位于對稱 NAT 之後時——那麼第三步中的最終連接配接将不會被允許。 由于初始連接配接是與 STUN 伺服器建立的,沒有其他對等方可以使用該連接配接資訊。在無法建立直接連接配接的情況下,我們需要使用 TURN 伺服器。

7.4.3 使用中繼繞過 NAT 的周遊(TURN)

TURN 是一種協定,用在無法在兩個對等點之間建立直接連接配接時中繼網絡流量。 例如,如果一個對等點位于對稱 NAT 之後,則需要一台專用伺服器來中繼對等點之間的流量。 在那種情況下,您将建立一個與 TURN 伺服器的連接配接,并告訴所有對等方将資料包發送到該伺服器,然後這些資料包将轉發給您。

這會帶來開銷,并且 TURN 伺服器的維護和運作成本可能很高。下圖說明了如何使用 TURN 伺服器在兩個或多個對等點之間中繼消息。

HTTP、WebSocket、gRPC 或 WebRTC:哪種協定最适合您的應用程式?

7.4.4 互動式連接配接建立(ICE)

ICE 使用 STUN 和 TURN 協定的組合,為主機提供一種機制來發現彼此的公共 IP 位址并建立直接連接配接。 如果無法直接連接配接,ICE 将使用 TURN 在兩台主機之間建立中繼連接配接。

所有這些可能建立連接配接的可能方式都稱為 ICE 候選者。 所有收集到的位址都通過 SDP 發送到遠端對等方,我們将在接下來進行探讨。 WebRTC 在每個用戶端上使用此資訊來确定連接配接到另一個對等點的最佳方式。 可能是兩個對等點都在同一個 NAT 上并且可以建立本地連接配接,或者可能是兩個對等點都在對稱 NAT 後面并且需要使用 TURN 伺服器的中繼。

7.4.5 會話描述協定 (SDP)

SDP 本質上是一種描述媒體會話的資料格式,用于會話公告、會話邀請和其他形式的會話發起。 它是描述連接配接的多媒體内容的标準,例如分辨率、格式、編解碼器和加密。

重要的是,它還用于描述 ICE 候選人和其他網絡選項。 當對等點 A 想要連接配接到對等點 B 時,他們需要共享 SDP 資訊才能連接配接。 這個 SDP 如何共享完全取決于——這被稱為信令,我們将在接下來探讨它。

7.4.6 Signaling-建立連接配接

信令是在兩個裝置之間發送控制資訊以确定通信協定、信道、媒體編解碼器和格式、資料傳輸方法以及任何所需路由資訊的過程。 關于 WebRTC 的信令過程,最重要的是要知道:它沒有在規範中定義。

對等連接配接處理連接配接不同計算機上的兩個應用程式。 連接配接是通過稱為信令的發現和協商過程建立的。

一個重要的警告是 WebRTC 沒有内置信号作為規範的一部分,因為兩個裝置不可能直接互相聯系,我們之前詳細探讨過這一點。 對于使用 WebRTC 連接配接的兩個對等點,它們需要彼此的 SDP 資料。

是以,作為開發人員,您有責任為兩個裝置建立一種共享此資訊的方式。 一個流行的選項是 WebSockets,或者可以通過電子郵件來回發送信令資訊或步行傳遞并手動輸入以建立連接配接。

一旦共享了此資訊,您就擁有了兩個對等點建立 WebRTC 連接配接所需的一切,它可能是直接連接配接,也可能是通過 TURN 伺服器。

7.5 什麼時候應該使用 WebRTC?

你甚至可能會問:我為什麼要使用 WebRTC? 了解起來似乎很複雜,設定起來更複雜。但有很多好處:

  • API 易于使用,可直接在您的浏覽器中使用。
  • 它具有良好的性能,可以傳輸高帶寬内容,例如視訊或音頻。
  • 可以輕松實作更多進階功能,例如螢幕共享和檔案共享。
  • 支援減少延遲的點對點連接配接。
  • 免費和開源。

但是 WebRTC 也有缺點:

  • 沒有内置信号。
  • 您需要維護 STUN 和 TURN 伺服器。
  • 對于群組連接配接(例如群組視訊通話),可能需要 SFU。
  • 設定和了解起來很複雜。

8.HTTP、WebSockets、gRPC、WebRTC 如何選擇?

具體選擇哪個協定要視情況而定,沒有一個統一的答案,但是可以從宏觀上對比下幾種協定。

HTTP:使用 HTTP/2 可以在用戶端和伺服器之間進行雙向通信。 對于某些應用程式,您可能不需要全雙工通信,像 SSE 這樣的東西就足夠了。 我們在本文中也發現 WebSockets 和 gRPC 依賴于 HTTP,而 WebRTC 也需要一些其他的信令通道。 在深入研究這些其他協定之前,值得首先探索 HTTP 是否能滿足您的實際需求。

WebSockets: 最适合需要雙向通信的實時應用程式,例如聊天應用程式, WebSockets 也相對容易設定和使用。 但是,WebSockets 的效率不如 gRPC 或 WebRTC,它們不太适合需要發送大量資料的應用程式。

gRPC: 是一種比 WebSockets 更高效的協定,更适合需要發送大量資料的應用程式。 但是,gRPC 的設定和使用比 WebSockets 更複雜。 如果你需要進行很多小的 API 調用,gRPC 是一個不錯的選擇。 或者,當你用各種需要通信的程式設計語言實作微服務時,那麼 gRPC 的序列化結構化資料和代碼生成會為你節省大量時間。 值得注意的是,您無法在浏覽器端輕松使用 gRPC,當然您可以手動引入 grpc-web。

WebRTC: 是浏覽器和裝置之間低延遲實時通信的最有效協定,非常适合需要發送大量資料的應用程式。 WebRTC 還提供了簡單易用的 API,可直接在浏覽器中使用,進而輕松共享您的相機、音頻、螢幕或其他檔案。 但是,WebRTC 的設定和使用可能很複雜,因為它需要您執行信号發送,維護 TURN 和 STUN 伺服器。

9.結論

未來将會看到更多的協定、變化和進一步的改進。目前 HTTP/3 已經釋出,還有一個名為 WebTransport 的新通信協定,它有可能替代 WebSockets。

參考資料

https://github.com/grpc/grpc-web

https://web.dev/webtransport/

https://levelup.gitconnected.com/http-websocket-grpc-or-webrtc-which-communication-protocol-is-best-for-your-app-1cc5a0786c86

https://web.dev/performance-http2/

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

https://medium.com/agora-io/how-does-webrtc-work-996748603141

https://getstream.io/blog/streaming-protocols/

https://getstream.io/blog/peer-to-peer-video-conferencing/

https://www.rfc-editor.org/rfc/rfc8441

https://chromestatus.com/feature/6251293127475200

https://docs.google.com/document/d/1ZxaHz4j2BDMa1aI5CQHMjtFI3UxGT459pjYv4To9rFY/edit

https://zhuanlan.zhihu.com/p/421503695

繼續閱讀