跳至主要內容
Skip to content

WebRTC 實戰 (2) —— 信令伺服器與連線中心

在上一篇中,我們成功獲取了本地的影音串流。現在問題來了:我要如何把我的影音傳給住在隔壁的朋友?

WebRTC 雖然常以點對點(P2P)方式傳輸媒體,但在連線建立前,雙方仍需要交換會話描述、網路候選路徑與控制訊息。負責交換這些資料的機制就叫做 信令(Signaling)


一、 信令:為什麼 P2P 需要伺服器?

想像你要和一個陌生人打電話,但你沒有對方的電話號碼。你們需要透過一個共同的朋友(信令伺服器)來交換彼此的聯絡方式。

1. 信令交換的流程 (Signaling Flow)

在 WebRTC 的連線建立階段,信令伺服器負責轉送以下三種資訊:

  1. 會話描述 (SDP):我是誰?我有什麼樣的影音編碼?
  2. 網路路徑 (ICE Candidates):我在哪裡?我的 IP 是什麼?
  3. 控制訊息:誰想打給誰?誰掛斷了?

二、 實作:極簡 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:實際資料,例如 RTCSessionDescriptionInitRTCIceCandidateInit

總結

今天我們學會了為什麼 P2P 連線需要先經過信令伺服器,以及信令交換的三大核心資訊。

下一篇,我們將深入探討當中最關鍵的「秘密協議」:RTCPeerConnection 與 SDP 交換。


進階挑戰

試著修改 server.js,增加一個功能:當某個使用者斷線時,自動通知所有正在與他通訊的對象。這需要你在 clients Map 中記錄更複雜的對應關係。


延伸閱讀與資源

← 上一章:瀏覽器影音採集 | 返回專題首頁 | 下一章:SDP 交換與媒體協商