本篇由 2019/9/7 撰寫之 https://5xruby.tw/posts/webrtc-unnamed-netowrk-chatroom/ 修改而來
筆者在 COSCUP 2019 講了 WebRTC 建立半分散式網路的一些心路歷程,結束之後使用此半分散式連線框架製作了一個界面看起來比較可以的聊天室,而且提供 Youtube 影片同步播放功能:
這邊的常駐 websocket peer 架設在免費的 heroku 上,網頁打開請等待
there are 1 neighbors... wss://un-wss-node-1.herokuapp.com
出現再進行操作,如果許久沒有出現可以重整一次試試
如何建立/加入群組:
聊天室使用以及 YOUTUBE 同步播放教學:
接下來是這個聊天室的連線框架(下面稱為 unnamed-network
)的心路歷程,也是 COSCUP 2019 WebRTC 半分散網路的投影片 整理出來的結果
如果不知道什麼是 WebRTC,可以參考去年寫的文章:https://5xruby.tw/posts/webrtc/
簡單來說 WebRTC 可以讓瀏覽器直接跟瀏覽器連線,但是連線的建立很麻煩,開發者要自己想辦法讓兩個瀏覽器交換 handshake 資訊 (offer, answer, ice)
上面的 DEMO 只有 STUN,就如同 這邊 所說,連線的兩者會受到雙方網路架構影響,例如 symetric NAT 的狀況就會導致 STUN 無法打通而無法連線
跟朋友一起做的遊戲專案 -- Bazaar,就如同下面這個影片這樣,可以有多個玩家在畫面上走來走去跳來跳去,移動等資訊就是透過 WebRTC 傳輸的
直接做全連線,首先用 websocket 跟伺服器 (wss) 連線,接著與所有玩家連線
這邊很快就會發現一件事,就是每個玩家的連線數是總玩家數 - 1,也就是說假設有 20 個人在場上,瀏覽器要建立 19 個連線...雖然沒有明定 WebRTC 的連線數限制...但是我自己後來做測試時大概 30 ~ 40 個連線時 chromium 會跟我說太多連線不允許建立更多連線
一個分散式的想法,把 websocket server 當成 client 看待,為了讓 browser 對待 server 就跟其他 browser 一樣,嘗試製作 WebRTC 跟 WebSocket 共用的界面
對於 wsConn 以及 rtcConn 來說,提供的功能就是送訊息以及接收訊息,很容易做成共用的界面
雖然兩者建立連線的方式有很大的不同,但是 WebRTC 連線建立其實就是需要一個節點幫忙傳送 handshaking 資料,於是試著蓋一層 peerConns,上面提供 API connect(peer, viaPeer)
peer
如果是 WebSocket URL,則不需要 viaPeer
,直接連線就好,而且就算給 viaPeer
也不會怎麼樣peer
如果是一個瀏覽器 (每個瀏覽器初始化時會自動產生一個 id),必須給上 viaPeer
指定一個節點幫忙傳送 handshaking 資料建立連線不過 bazaar 遊戲到目前為止
viaPeer
永遠會是 wss
WebRTC 連線一定會需要一個節點幫忙做連線,因此
後來可以透過瀏覽器幫忙連線,因此
舉個例子來跑一次看看:
雖然第一個連線一定是 WebSocket,不過還是可以某種程度的降低對 WebSocket server 的依賴性,於是就開始嘗試把整個連線的東西抽出來做...
總結前面的想法,這個東西暫時叫他 unnamed-network
,抽成一個專案並且:
unnamed-network
專案:unnamed-network
的架構connect(peer, viaPeer)
給上層使用因為 wss 也只是一個 client 了,wss 也很有可能會想要主動與他人連線,列舉一下整理成四種情況:
左下連右上 | wss | browser |
---|---|---|
wss | ws 直連 | 邀請連 ws 🤝 |
browser | ws 直連 | WebRTC 🤝 |
這邊比較有趣的就是『當 wss 想要連到 browser』的狀況,這邊想到的方法是透過 viaPeer 邀請 browser 來連 wss;需要 viaPeer 的部份標上 🤝
,所以結論來說不是只有 WebRTC 會需要 viaPeer
這就是還很不完善的部份了,這邊就稍微講一下目前運作的行為
"/"
群組"/"
請求 route-group
沒關係這邊有簡易的案例:
group1
有三個人,其中 chrome 與 wss 連線"/"
群組時會去找 wss 連線"/"
群組的節點詢問 route-group
group1
怎麼走,因此對著 wss 發問"/"
群組的節點詢問 route-group
group1
怎麼走,因為詢問來自 safari,因此對著 chrome 發問group1
,回覆自己的 idgroup1
,因此透過 wss 與 chrome 進行 WebRTC 連線並請求加入 group1
group1
不過這個網路顯然大家會來來去去的,safari 只跟 group1 保持一個連線感覺很危險,所以加上 neighbor 數量維護的機制,每個節點自己會盡可能維持一個群組內的連線數(也就是鄰居 neighbor 數)在 3 - 6 個之間:
3
,低於這個數量會嘗試尋找更多 neighbor6
,高於這個數量會去減少 neighbor 數量10
,不接受更多連線100
避免加入不了網路所以舉例來說:
group1
是否還有其他人花了這麼多力氣建立了網路...總得來送些訊息吧?群組廣播的時候發起廣播的節點需要附上隨機的 msgId
然後送給 neighbors,收到廣播訊息的節點先看一下 msgId
是否有看過,如果看過就不要理他,反之則觸發事件告訴更上面的 application 層並且繼續傳遞自己的其他 neighbors,一樣舉個例子:
msgId
為 123
,傳送給 chrome, firefox 與另一個 safarimsgId
123
,則會避免繼續再把訊息散布下去不過如果有 neighbor 離開, 斷線又或是一堆人離開的時候,還沒有想到一個好方法避免孤島產生,目前的方式就是重新找 wss 加入群組,其實是很沒效率而且很容易出問題的方法...所以這個網路或許建立連線的時候還行,但如果要在人來來去去的情況下持續運作是肯定有問題的
unnamed-network
能用的話需要...個人是期望這個 network 可以做到這些事情:
如果看完有興趣歡迎來按個星星讓我知道這個東西可以繼續做,或是透過我的個人網站 https://pastleo.me/ 上的聯絡方式找到我,感謝各位的閱讀!