LinSoap

LinSoap

Null
github
x

使用JS透過WebRTC創建libp2p網絡並相互連接(理論)

最近發現一個好玩的資料庫專案 OrbitDB,想做一個去中心化的公共動漫元資料庫,但其去中心化的實現方式是通過 libp2p 的方式實現的,在開發過程中最難理解和設置的就是 libp2p 相關的內容了,好在這兩週官方更新了一篇質量很高的入門教程,能學習到非常多的相關知識。值得我開一篇博客總結一下內容。
WebRTC with js-libp2p

為什麼選擇 WebRTC#

什麼是 WebRTC#

WebRTC,名稱源自網頁即時通信(英語:Web Real-Time Communication)的縮寫,是一個支持網頁瀏覽器進行實時語音對話或視頻對話的 API。通過 WebRTC 可以實現瀏覽器到瀏覽器直接的 P2P 連接,允許兩個瀏覽器之間直接進行資料傳輸,並且在目前主流的瀏覽器中都已經支持 WebRTC 協議,配合 js-libp2p 可以直接讓瀏覽器當作 libp2p 節點加入 libp2p 網路。

libp2p 網路拓撲

JS-libp2p 連通性和連通能力#

libp2p 有很多語言實現方案,但是各個方案目前的實現程度和局限性各不相同,官網提供了目前各語言的實現進度和局限性。
libp2p 實現進度

各語言實現進度
由於瀏覽器的限制,瀏覽器無法直接通過 TCP 和 QUIC 協議進行傳輸,想要在瀏覽器中創建獨立的 libp2p 節點,目前來看只有 3 個協議可以選擇,分別是 WebSocket、WebTransport、WebRTC。然後官網還給出了 libp2p 各協議之間的連通性結果並解釋了為什麼瀏覽器不支持 TCP 和 QUIC 協議
libp2p 各協議間連通性

瀏覽器局限性

瀏覽器到瀏覽器連通性
從官網給出的連通性結果,目前 WebSocket 和 WebTransport 只能支持連接到伺服器,並不支持連接到瀏覽器,目前為止在所有實現方案中,只有 js-libp2p 配合 WebRTC 能夠實現將瀏覽器視為獨立的節點。

WebRTC 的局限性和解決方案#

在進行 P2P 連接的時候,最重要的問題是如何讓兩個瀏覽器相互發現對方,使得節點能夠進行後續的連接。為此提供了兩個解決方案,分別是 STUN 伺服器和 TURN 伺服器。

  • STUN 伺服器:由於網路中有很多的 NAT 結構,使得瀏覽器很難直接通過公網地址發現對方,STUN 伺服器就是幫助瀏覽器相互發現各自節點,以便於建立相互的連接的伺服器,其中有很多免費的公共 STUN 伺服器可以選擇。
    免費的 STUN 公共伺服器
  • TURN (Relay) 伺服器:如果通過瀏覽器之間無法建立直接的 P2P 連接,即 STUN 服務使得節點相互發現了但仍然無法連接,則可以通過 TURN 伺服器轉發 P2P 連接的所有流量,也因此 TURN 的使用成本較高,不是很好的選擇。

在瀏覽器進行 P2P 連接的時候,相互可能需要發送一些元數據信息或者對話描述信息,即信令(Signaling)交換。在 WebRTC 標準中沒有強制規定這些內容。需要開發者自己去實現信令交換方案。
在 libp2p 中,設計了一個新的方案去解決以上兩個問題。通過一個 libp2p relay 節點解決。libp2p relay 節點在網路中充當兩個角色,分別為:

  • Circuit Relay V2:在瀏覽器節點無法直接建立 P2P 連接的時候,選擇 TURN 服務的成本有太高,Circuit Relay V2 就能夠很好地解決這個問題,因為他是去中心化的,讓網路中活躍的節點幫助瀏覽器相互發現彼此,在無法進行 P2P 連接的時候轉發所需的流量。
  • PubSub Peer Discovery:以上內容解決了節點之間能否連通的問題,而 PubSub Peer Discovery 就是解決了節點之間自動相互連接的問題。GossipSub 模式就是 PubSub Peer Discovery 的一個實現方案,節點通過訂閱一個主題,每當有一個新的節點加入,並訂閱了相同主題,那麼 PubSub Peer Discovery 會向所有訂閱該主題的節點廣播新節點地址,各節點接受到地址後會嘗試與其連接。但需要注意,在一個大型網路中,發送廣播是一個資源消耗很大的行為,不合理使用很可能會導致堵塞進而失去可靠性,所以該方案可能不適合在生產環境中使用。

連接流程#

關於兩個節點如何創建 P2P 連接,以及 libp2p relay 節點在鏈接中起到什麼作用,官方給出了一張流程圖大致描述了工作流程。

連接流程圖
關於該流程,大致思路為,兩個節點在建立連接的時候,需要先知道 Relay 節點的地址,與 Relay 節點發起 WebSockets 連接,當兩個節點成功與 Relay 節點建立穩定連接後,並且訂閱了 GossipSub 相同的主題後,Relay 節點會通過 Circuit Relay V2 向網路中訂閱了相同主題的節點告知對方的多地址(multiaddr)。多地址是形如以下的地址,

//一個節點的多地址(multiaddr)
//使用WebSocket 端口9001 支持WebRTC
/ip4/127.0.0.1/tcp/9001/ws/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ/p2p-circuit/webrtc/p2p/12D3KooWR3oBwBzZxSTd5RTKGJC2WsCxqWumpBUP1WjsixjeMQ9s
//不使用WebSocket 端口9002 支持WebRTC
/ip4/127.0.0.1/tcp/9002/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ/p2p-circuit/webrtc/p2p/12D3KooWR3oBwBzZxSTd5RTKGJC2WsCxqWumpBUP1WjsixjeMQ9s
//使用WebSocket 端口9001 不支持WebRTC
/ip4/127.0.0.1/tcp/9001/ws/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ/p2p-circuit/p2p/12D3KooWR3oBwBzZxSTd5RTKGJC2WsCxqWumpBUP1WjsixjeMQ9s
//不使用WebSocket 端口9002 不支持WebRTC
/ip4/127.0.0.1/tcp/9002/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ/p2p-circuit/p2p/12D3KooWR3oBwBzZxSTd5RTKGJC2WsCxqWumpBUP1WjsixjeMQ9s

最後兩個節點會通過多地址嘗試建立 WebRTC 連接,完成 P2P 連接。

官方還給出了一張更加詳細的 WebRTC 連接流程。

詳細連接流程圖
在通過 libp2p relay 節點互相發現對方後,要開始建立 WebRTC 連接了。首先每個節點會從 STUN 伺服器獲取自身的公共 IP 和端口。然後連接發起節點會根據 STUN 返回的信息創建 RTCPeerConnection 對象(這是一個用於管理 WebRTC 連接狀態的對象)並創建 DataChannel 和 SDP(Seesion Description Protoncol,用於描述對話信息)準備發起連接。連接發起者會創建一個 libp2p 中定義的信令(webrtc-singnaling)通過 libp2p Relay 節點向被連接方發送 SDP,當被連接方接受到 SDP 後,同樣也會創建一個 RTCPeerConnection 和 SDP 回覆給發送方,發送方接受到 SDP 後並記錄,至此兩個節點完成握手交換 SDP 信息。
然後通過 ICE(Interactive Connectivity Establishment,用於在 P2P 連接中找到最佳連接路徑)將對方節點添加到連接管理對象 RTCPeerConnection 中。最後通過 Noise(一種加密通信協議)加密連接通道完成連接。

至此已經大致了解在 libp2p 中是如何通過 WebRTC 解決瀏覽器節點直接連接的問題,其中涉及到很多名詞在以前並不是很了解,所以出現矛盾和差錯以官方資料為準。

WebRTC with js-libp2p
libp2p Connectivity
Peers - libp2p
SDP - MDN Web
mutiaddr - libp2p
WebRTC - MDN Web
Circuit Relay - libp2p
lib2p2 signaling-protocol -Github
js-libp2p-pubsub-peer-discovery -Github

至此理論文章已經結束,為了更深入的了解其中的內容,可以繼續閱讀實踐文章
使用 JS 通過 WebRTC 創建 libp2p 網路並相互連接(實踐)

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。