WebRTC 實戰 (2) —— 信令伺服器與連線中心
在上一篇中,我們成功獲取了本地的影音串流。現在問題來了:我要如何把我的影音傳給住在隔壁的朋友?
WebRTC 雖然常以點對點(P2P)方式傳輸媒體,但在連線建立前,雙方仍需要交換會話描述、網路候選路徑與控制訊息。負責交換這些資料的機制就叫做 信令(Signaling)。
一、 信令:為什麼 P2P 需要伺服器?
想像你要和一個陌生人打電話,但你沒有對方的電話號碼。你們需要透過一個共同的朋友(信令伺服器)來交換彼此的聯絡方式。
1. 信令交換的流程 (Signaling Flow)
在 WebRTC 的連線建立階段,信令伺服器負責轉送以下三種資訊:
- 會話描述 (SDP):我是誰?我有什麼樣的影音編碼?
- 網路路徑 (ICE Candidates):我在哪裡?我的 IP 是什麼?
- 控制訊息:誰想打給誰?誰掛斷了?
二、 實作:極簡 WebSocket 信令伺服器
我們使用 Node.js 的 ws 套件建立一個最小可用的轉發中心。這裡先統一系列後續會沿用的訊息格式:
javascript
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 8080 });
const clients = new Map();
wss.on("connection", (ws) => {
ws.on("message", (message) => {
let data;
try {
data = JSON.parse(message.toString());
} catch {
ws.send(JSON.stringify({ type: "error", payload: "Invalid JSON" }));
return;
}
const { type, to, from, payload } = data;
if (type === "login" && from) {
clients.set(from, ws);
ws.userId = from;
return;
}
if (!["offer", "answer", "candidate"].includes(type)) return;
const targetSocket = clients.get(to);
if (targetSocket?.readyState === WebSocket.OPEN) {
targetSocket.send(JSON.stringify({ type, from, to, payload }));
}
});
ws.on("close", () => {
if (ws.userId) clients.delete(ws.userId);
});
});這個版本只適合教學。正式環境還需要驗證使用者身分、限制訊息大小與頻率,並確認 from 不可由客戶端任意冒用。
三、 實作細節:JSON 封裝規範
為了讓信令能準確轉發,前端傳送的訊息格式至少需要包含:
type:訊息種類 (offer, answer, candidate, login)。from:發送者 ID。to:接收者 ID。payload:實際資料,例如RTCSessionDescriptionInit或RTCIceCandidateInit。
總結
今天我們學會了為什麼 P2P 連線需要先經過信令伺服器,以及信令交換的三大核心資訊。
下一篇,我們將深入探討當中最關鍵的「秘密協議」:RTCPeerConnection 與 SDP 交換。
進階挑戰
試著修改 server.js,增加一個功能:當某個使用者斷線時,自動通知所有正在與他通訊的對象。這需要你在 clients Map 中記錄更複雜的對應關係。
延伸閱讀與資源
- WebRTC.org: Signaling
- Socket.io Documentation: Room Implementation