信令

信令是实现一对一通信的重要一环,如创建房间、退出房间等都会用到信令。但 WebRTC 1.0 规范文档中没有对信令做任何定义,这是怎么回事呢?究其原因,是因为信令与业务逻辑密切相关,不同业务逻辑的信令也会千差万别,将其定义到规范里显然是费力不讨好的事情。因此,不如不做约束,让大家根据自己的业务定义信令,而 WebRTC 只聚焦在服务质量上,这样反而效果更好。

信令定义

要实现一对一通信,驱动系统运转的核心就是信令。信令控制着系统各模块之间的前后调用关系。比如当收到用户成功加入房间的信令后,系统需要立即将 RTCPeerConnection 对象创建好,以便向 STUN/TURN 服务器请求其外网的IP地址和端口;而当收到另一个用户加入房间的消息时,系统需要将自己的外网 IP 地址和端口交换给对方,从而建立起 socket 连接,等等。

下面具体看一下要实现一对一通信,最简单的信令系统应该如何设计。在这个例子中,我们将信令分成两大类:第一类为客户端发送给服务端的信令;第二类为服务端发送给客户端的信令。各信令含义如表 4.1 所示。

image 2025 02 22 23 56 44 252
Figure 1. 表4.1 信令系统

信令时序

表 4.1 中的信令已经足够简单了,共 8 个信令。这 8 个信令还是比较好理解的,例如,当用户要进行通信,加入 “房间” 时,会向信令服务器发送 join 信令。信令服务器收到该信令后,先将该用户加入服务器管理的房间里,然后向客户端返回 joined 信令,表示该用户已经成功加入房间了。这就是 join 信令与 joined 信令的作用,一个用于请求加入房间,另一个用于成功应答。其他的信令与这两个信令是类似的。

图4.3 清楚地表达了各信令之间的时序关系。在发送信令之前,各端要先与信令服务器 SigServer 建立连接。连接建立好后,终端 Caller 会向信令服务器发送 join 消息,服务器收到该消息后,返回 joined 消息,表示该用户已经成功加入房间;当第二个终端 Callee1 成功加入后,第一个终端 Caller 还会收到 otherjoin 消息,表示第二个用户也成功加入了;之后,CallerCallee1 进行媒体协商(媒体协商会在第 5 章介绍),即通过 message 消息交换 WebRTC 需要的 offer/answer 等内容;当媒体协商成功后,双方就可以进行音视频通信了;如果此时有第三个用户 Callee2 请求加入,信令服务器发现房间里已经有两个用户了,则会给 Callee2 返回 full 消息,告诉它当前房间已满,不能再加入了。

同样地,在用户离开时,需要向服务器发送 leave 消息,服务器收到后返回 left 消息。客户端收到 left 消息说明服务器已经将它从房间中移除了。同时,服务器还会向另一方发送 bye 消息,通知它与它通话的用户已经走了,可以释放相关的资源了。以上就是信令的时序和它们之间的逻辑关系。

image 2025 02 23 00 00 37 626
Figure 2. 图4.3 信令时序图

信令传输协议的选择

我们一般选择 TCP 或基于 TCPHTTP/HTTPSWS/WSS 等协议作为信令服务器的传输协议。这样做有两点好处:一是不用担心信令丢失,因为 TCP 是可靠的传输协议,能保证传输的数据可靠、有序到达;二是在 TCP 上传输的数据是流式的,因此不必担心传输的数据过大导致拆包传输的问题,虽然 TCP 协议层处理了物理拆包,但应用层仍需解决逻辑消息的边界问题(如粘包和拆包导致的消息不完整)

当然,也可以选择 UDP 来实现信令的传输。但由于 UDP 是基于包的不可靠传输协议,所以需要你自己处理丢包、乱序、拆包重组等一系列问题,这将导致很多额外的工作。