{%hackmd SyQbZi4Mr %}
用 WebRTC 建立半分散式網路
===
#### By [PastLeo](https://pastleo.me), a developer from [5xruby](https://5xruby.tw)
---
## WebRTC 是什麼?
### Web Real-Time Communication
https://5xruby.tw/posts/webrtc/
---
## 跟 WebSocket 的差別是?
| WebSocket | WebRTC |
|---------------|----------------|
| tcp (http) | udp by default |
| client-server | peer-to-peer |
---
### Web Real-Time Communication
<img class='svg' src='https://static.pastleo.me/assets/1908141135.svg'>
* Video/Audio conferencing
* Data channel
---
### Web Real-Time Communication
<img class='svg' src='https://static.pastleo.me/assets/1908141135.svg'>
* ~~Video/Audio conferencing~~
* Data channel
---
## WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817225726.svg'>
---
## WebRTC 連線建立
1. Signaling
2. Interactive Connectivity Establishment,ICE
---
### Signaling
<img class='svg' src='https://static.pastleo.me/assets/190817225743.svg'>
---
### Signaling
<img class='svg' src='https://static.pastleo.me/assets/190817225835.svg'>
---
### Signaling
<img class='svg' src='https://static.pastleo.me/assets/190817225908.svg'>
---
### Signaling
<img class='svg' src='https://static.pastleo.me/assets/190817225948.svg'>
---
### Signaling done
<img class='svg' src='https://static.pastleo.me/assets/190817230015.svg'>
---
## ICE
<img class='svg' src='https://static.pastleo.me/assets/190817230032.svg'>
---
## WebRTC connection ready!
<img class='svg' src='https://static.pastleo.me/assets/1908141135.svg'>
`iceConnectionState: "completed"`
---
## 如何傳送 signaling 以及 ICE?
```json
{"type":"offer","sdp":"v=0\r\no=- 808320459780741931 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:sPNA\r\na=ice-pwd:TW1+woGkN85ZdM0J9s1rDb/g\r\na=ice-options:trickle\r\na=fingerprint:sha-256 61:2F:11:89:BD:82:81:48:54:CD:6C:CE:31:87:F9:40:36:CB:BA:CA:BB:DA:C8:9C:40:38:9E:AD:3B:EC:69:0F\r\na=setup:actpass\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"}
```
```json
{"type":"answer","sdp":"v=0\r\no=- 1665667491633561454 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=ice-ufrag:mAPp\r\na=ice-pwd:LfCCIhM35ejCm+bC/D7I263C\r\na=ice-options:trickle\r\na=fingerprint:sha-256 4E:58:CB:0A:9F:EF:78:BA:C0:A3:AB:32:14:14:C0:69:1B:A9:18:AC:04:27:6F:4E:1B:90:35:4D:40:07:41:63\r\na=setup:active\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"}
```
```json
{"candidate":"candidate:842163049 1 udp 1677729535 223.137.53.226 23733 typ srflx raddr 10.203.94.37 rport 38103 generation 0 ufrag HvAq network-cost 999","sdpMid":"0","sdpMLineIndex":0}
```
#### <span style="color: transparent;">_</span>
---
## 如何傳送 signaling 以及 ICE?
```json
{"type":"offer","sdp":"v=0\r\no=- 808320459780741931 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:sPNA\r\na=ice-pwd:TW1+woGkN85ZdM0J9s1rDb/g\r\na=ice-options:trickle\r\na=fingerprint:sha-256 61:2F:11:89:BD:82:81:48:54:CD:6C:CE:31:87:F9:40:36:CB:BA:CA:BB:DA:C8:9C:40:38:9E:AD:3B:EC:69:0F\r\na=setup:actpass\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"}
```
```json
{"type":"answer","sdp":"v=0\r\no=- 1665667491633561454 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=ice-ufrag:mAPp\r\na=ice-pwd:LfCCIhM35ejCm+bC/D7I263C\r\na=ice-options:trickle\r\na=fingerprint:sha-256 4E:58:CB:0A:9F:EF:78:BA:C0:A3:AB:32:14:14:C0:69:1B:A9:18:AC:04:27:6F:4E:1B:90:35:4D:40:07:41:63\r\na=setup:active\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"}
```
```json
{"candidate":"candidate:842163049 1 udp 1677729535 223.137.53.226 23733 typ srflx raddr 10.203.94.37 rport 38103 generation 0 ufrag HvAq network-cost 999","sdpMid":"0","sdpMLineIndex":0}
```
#### ...開發者要自己想辦法
---
#### My "hello world" to WebRTC
![chatroom screenshot](https://i.imgur.com/CgzqBtG.png)
用 [Elixir](https://elixir-lang.org/), [Phoenix](https://phoenixframework.org/) 寫的 WebSocket server
---
## 等等,網路問題怎麼克服的?
#### 被 NAT 隔開還能用嗎?
---
## STUN & TURN
1. [Session Traversal Utilities for NAT, STUN](https://zh.wikipedia.org/wiki/STUN), 用 [UDP hole punching](https://en.wikipedia.org/wiki/UDP_hole_punching) 克服 NAT 的限制
2. [Traversal Using Relay NAT, TURN](https://zh.wikipedia.org/wiki/TURN)
```javascript
new RTCPeerConnection({
iceServers: [
{urls: 'stun:stun.l.google.com:19302'}
]
});
```
---
## [caniuse?](https://caniuse.com/#search=webrtc)
* Firefox, Chrome: supported on 2013 and 2012
* safari / iOS safari: supported on 2017/9 (iOS 11)
* Edge: no RTCDataChannel, but new chromium-based Edge is on the way
* IE: sorry nope
---
### Multiplayer game using WebRTC
#### Bazaar
![](https://static.pastleo.me/assets/bazaar-coscup-demo.gif)
---
## Bazaar client 之間的連線方法
#### 用 websocket 跟伺服器連線,接著與所有玩家連線
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817230331.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817231357.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817231421.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817231441.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817231856.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817231922.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817231942.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817232006.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817232026.svg'>
---
### Bazaar client 之間的連線方法
<img class='svg' src='https://static.pastleo.me/assets/190817232046.svg'>
---
## 想說 server 可以是一個 NPC...
#### 把 server 當成 peer 看待?
---
### rtc 與 ws 共用的 interface
<img class='svg' src='https://static.pastleo.me/assets/190815150840.svg'>
---
### rtc 與 ws 共用的 interface
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815154445.svg'>
</div>
<div class="column-1">
#### <span style="color: transparent;">_</span>
* startLink(...args)
* send(...message)
* on('receive', callback)
</div>
</div>
---
### rtc 與 ws 共用的 interface
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815154614.svg'>
</div>
<div class="column-1">
#### <span style="color: transparent;">_</span>
* connect(peer, <span style="color: red">viaPeer</span>)
* send(peer, ...message)
* on('receive', callback)
</div>
</div>
---
### rtc 與 ws 共用的 interface
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815154614.svg'>
</div>
<div class="column-1">
* connect(peer, <span style="color: red">viaPeer</span>)
* send(peer, ...message)
* on('receive', callback)
<img class='svg' src='https://static.pastleo.me/assets/190815153930.svg'>
</div>
</div>
---
### 透過 browser 進行 WebRTC 連線建立
#### 會是什麼樣子?
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233057.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233229.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233318.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233343.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233405.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233442.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
<img class='svg' src='https://static.pastleo.me/assets/190817233504.svg'>
---
### 透過 browser 進行 WebRTC 連線建立
* 第一個連線一定是 WebSocket
* 加入網路之後可以關閉 WebSocket 連線
---
## 半分散式網路
### unnamed-network?
---
### unnamed-network?
* 改成 general WebSocket
* 實做 nodejs 版本 Websocket server
* 接下來簡稱 wss
* wss 是個 client, 網路中同時可以有複數個
* 群組功能
* 一個 client 可以同時加入多個 group
* 群組廣播
---
### unnamed-network 架構
<img class='svg' src='https://static.pastleo.me/assets/190815183330.svg'>
---
#### unnamed-network 架構
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815183453.svg'>
</div>
<div class="column-1">
#### <span style="color: transparent;">_</span>
* startLink(args)
* send(...message)
* on('receive', callback)
</div>
</div>
---
#### unnamed-network 架構
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815183813.svg'>
</div>
<div class="column-1">
#### <span style="color: transparent;">_</span>
* connect(peer, opts)
* on(‘new’, callback)
</div>
</div>
---
#### unnamed-network 架構
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815184426.svg'>
</div>
<div class="column-1">
* connect(peer, opts)
* opts: { viaPeer }
* on('ready', callback)
* send(peer, ...message)
* on('receive', callback)
</div>
</div>
---
#### unnamed-network 架構
#### connManager 連線建立策略
| 左下連右上 | wss | browser |
|----------|--------|--------------|
| wss | ws 直連 | 邀請連 ws (!) |
| browser | ws 直連 | WebRTC (!) |
(!): 需要 viaPeer
---
#### unnamed-network 架構
<div class="grid">
<div>
<img class='svg' src='https://static.pastleo.me/assets/190815190347.svg'>
</div>
<div class="column-1">
* join(group)
* leave(group)
* broadcast(group, term, payload)
* on(term, callback)
</div>
</div>
---
### unnamed-network 目前設計
#### 初始化
* 有一個 known list 紀錄 wss
* 所有 client 都會加入 `"/"` 群組
---
### unnamed-network 目前設計
#### 加入群組
* 對 `"/"` 請求 `route-group`
* max hops: 10
* 加入群組時發現找不到人就是建立新群組
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816015615.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816015700.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816015721.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816020442.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816020531.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816020608.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816015905.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816015947.svg'>
---
### unnamed-network 目前設計
#### 初始化 & 加入群組
<img class='svg' src='https://static.pastleo.me/assets/190816020024.svg'>
---
### unnamed-network 目前設計
#### neighbors 數量維護
* 低水位: 3
* 低於這個數量會嘗試尋找更多 neighbor
* 高水位: 6
* 高於這個數量會去減少 neighbor 數量
* 滿水位: 10
* 不接受更多連線
* wss 的滿水位: 100
---
### unnamed-network 目前設計
#### neighbors 數量維護
<img class='svg' src='https://static.pastleo.me/assets/190816021651.svg'>
---
### unnamed-network 目前設計
#### neighbors 數量維護
<img class='svg' src='https://static.pastleo.me/assets/190816021732.svg'>
---
### unnamed-network 目前設計
#### neighbors 數量維護
<img class='svg' src='https://static.pastleo.me/assets/190816021750.svg'>
---
### unnamed-network 目前設計
#### neighbors 數量維護
<img class='svg' src='https://static.pastleo.me/assets/190816034139.svg'>
---
### unnamed-network 目前設計
#### neighbors 數量維護
<img class='svg' src='https://static.pastleo.me/assets/190816021825.svg'>
---
### unnamed-network 目前設計
### 群組廣播
* 送出訊息時,附加上隨機的 `msgId`
* 如果已經看過這個 `msgId` 就 drop 掉訊息
---
### unnamed-network 目前設計
#### 廣播/群組請求
<img class='svg' src='https://static.pastleo.me/assets/190816030004.svg'>
---
### unnamed-network 目前設計
#### 廣播/群組請求
<img class='svg' src='https://static.pastleo.me/assets/190816030031.svg'>
---
### unnamed-network 目前設計
#### 廣播/群組請求
<img class='svg' src='https://static.pastleo.me/assets/190816030059.svg'>
---
#### unnamed-network
### 有 neighbor 離開或是斷線時
## ...
---
#### unnamed-network
### 有 neighbor 離開或是斷線時
## 目前還沒有好方法避免孤島產生
---
### 要讓這個 network 能用的話需要...
* 能跨多個 node 進行連線以增加多 hop 連線效率
* 分散式,並且同時可以避免孤島產生的機制
* [Distributed hash table](https://zh.wikipedia.org/wiki/%E5%88%86%E6%95%A3%E5%BC%8F%E9%9B%9C%E6%B9%8A%E8%A1%A8) 可能是解法之一
* 解決安全性問題
* 釋出為一個連線框架
---
### DEMO [link](https://static.pastleo.me/unnamed-network-coscup2019/)
![](https://static.pastleo.me/assets/un-coscup-demo.gif)
---
### 期望這個 network 可以...
* 使得瀏覽器不用安裝任何 plugins / add-ons 就可以使用分散式應用程式
* 降低架設 wss 的技術門檻,人人都可以成為網路進入點
* 讓不同應用程式可以共用這個 network 來建構多人遊戲、共筆系統等
---
### Git Repos
#### https://github.com/pastleo/unnamed-network
另外兩個前面提到的專案:
* https://github.com/pastleo/webrtc-phx
* https://github.com/pastleo/bazaar
---
## Thank you!
### link to this slides
### https://ppt.cc/fG58Hx
### Any questions?
<style>
.reveal section img.svg {
border: none;
box-shadow: none;
}
.reveal section table {
color: #004a1b;
}
.reveal section table th, .reveal section table td {
border: #004a1b solid 1px;
border-bottom: #004a1b solid 1px;
}
.reveal section table tbody tr:last-child th, .reveal section table tbody tr:last-child td {
border-bottom: #004a1b solid 1px;
}
.grid {
display: flex;
flex-direction: row;
}
.grid .column-1 {
flex: 1;
}
</style>
{"metaMigratedAt":"2023-06-15T10:11:25.584Z","metaMigratedFrom":"YAML","title":"用 WebRTC 建立半分散式網路","breaks":true,"slideOptions":"{\"spotlight\":{\"enabled\":true,\"size\":80,\"presentingCursor\":\"default\",\"toggleSpotlightOnMouseDown\":false,\"spotlightOnKeyPressAndHold\":90,\"initialPresentationMode\":true,\"disablingUserSelect\":false,\"fadeInAndOut\":500},\"allottedMinutes\":5}","contributors":"[{\"id\":\"0eb274f7-a3a4-4c8e-b0d4-e5c08eaf9e72\",\"add\":14363,\"del\":70}]"}