想象你刚到一座陌生城市,约了一位刚认识的朋友见面喝咖啡。你不知道他住哪栋楼,也没存过他的手机号,连他到底在不在同一个城区都不确定。唯一能指望的,是你们恰好认识同一位“城市邮局的管理员”。于是你们先托管理员互传名片——名片上写着各种可联系地址:办公室座机、手机、小区快递柜、前台的转告电话。拿到名片后,你按顺序试拨:手机通了就直接聊,不通就试座机,再不行去快递柜留言,最不济请邮局的人帮忙转交。这套“传名片、试拨号、兜底中转”的流程,正是 WebRTC 里“信令服务器与 ICE 候选收集”在做的事:信令服务器是那座邮局,ICE 是那套试拨手册,NAT、STUN、TURN 则是城市里的收发室、电话局和公共中转站。读完这篇,你会从零理解一次音视频通话是怎样从“互不相识”走到“顺利连线”的。

岗位关联

信令与 ICE 决定了 WebRTC 的接通率和建连速度,是实时音视频项目中排查“打不通、卡爆音”的第一站。掌握它,你能独立设计信令协议、定位 NAT 穿透问题,并为 AI 音视频应用选型给出有理有据的工程判断。

目录
  1. 可视化演示
  2. 信令协议设计
  3. 候选类型分析
  4. 连通性检查
  5. 失败重试机制
  6. 生产部署路径
  7. 工程实践建议
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示WebRTC信令服务器架构:两个客户端通过信令服务器交换SDP Offer/Answer,收集host/srflx/relay三类ICE候选并进行连通性检查建立P2P连接。支持信令流程与候选类型两种模式。

本节配有交互动效(进入视口后自动加载,约 3KB)。

WebRTC信令交换与ICE候选收集 信令服务器中转SDP Offer/Answer协商 ICE收集host/srflx/relay候选并检查连通性 ICE=STUN+TURN+ConnCheck ICE框架实现NAT穿透

信令协议设计

邮局要帮忙送信,必须先有一套统一的“信封规范”:收件人写在哪、寄件人是谁、信纸怎么折,邮差才不会送错。WebRTC 里的信令协议正是这套规范。它不传输画面和声音,只负责在通话双方之间传递“自我介绍”和“约定事项”——双方各有什么能力、想用什么格式通话,都靠它来对齐。

信令的核心载体是 SDP(Session Description Protocol)会话描述。它像名片上的一句话:“我会说普通话和粤语,你选一个。”一方先发出 Offer,说明自己支持的音视频编码、码率、传输端口;另一方收到后回应 Answer,表示接受并补充自己的参数。这个一来一回的过程,就是 Offer/Answer 协商,也是所有通话开始前的“打招呼”。

信令通道最常用的载体是 WebSocket:双向、全双工、低延迟,天然适合持续交换小消息。一条信令消息通常是一个 JSON 对象,包含 type(消息类型:offer/answer/ice-candidate/bye 等)、from/to(发送方与接收方)、payload(SDP 或候选数据)、seq(序号,防止乱序)。光有格式还不够,还要有状态机:空闲 → 已发 Offer → 已收 Answer → 连接中 → 已连接,每一步都配超时和异常分支,防止“聊到一半失联”。

所以“邮票”和“信封”看起来琐碎,却决定了整封信能否准时送达。信令协议设计得好,就等于给后续的 ICE 环节铺了一条最顺的路——邮局这条线稳了,接下来的“找地址、试电话”才有意义。

Tsetup≈3×RTTws+TICE\displaystyle T_{setup} \approx 3 \times RTT_{ws} + T_{ICE}
建连时间约等于三次 WebSocket 往返(Offer、Answer、确认)加上 ICE 候选收集与检查的并行等待时间。信封写得越规范、邮差跑得越快,通话建立就越快。
  1. 三次往返Offer、Answer、最终确认各占一次 WebSocket 往返时延,这是信令协商的最小开销。
    3×RTTws\displaystyle 3 \times RTT_{ws}
  2. ICE 并行开销候选收集与连通性检查可以和信令交换同时进行,公式取其最长路径的等待时间。
    +  TICE\displaystyle + \; T_{ICE}
  3. 优化方向若网络 RTT 大或信令服务器处理慢,建连时间会明显变长,因此生产上优先选择 WebSocket 并就近部署节点。
    Tsetup→min⁡\displaystyle T_{setup} \to \min

候选类型分析

名片上的联系地址写得越全,找到对方的概率就越大。ICE 候选就是“名片上的地址”,一共三类。host 主机候选,像你办公桌上的座机——直接用本机网卡的 IP 和端口,最直接最快速,但只有在同一局域网内才能打通;srflx 反射候选,像收发室保安告诉你“外人拨这个号码能找到你”——你向 STUN 服务器问出自己在外网被看到的地址;relay 中继候选,则是城市公共快递柜的地址——谁都能用,但总归要绕一段路。

收集这三类地址的做法各不相同:主机候选直接枚举本机所有网卡(WiFi、4G、虚拟网卡),一条网络一个;反射候选需要向 STUN 服务器发送 Binding 请求,服务器会回答“从外面看,你的地址是 xxx:端口”;中继候选则是向 TURN 服务器申请一个转发地址,TURN 服务器把媒体包接力转给对端,代价是消耗服务器带宽。

既然地址有“快慢优劣”,就得排个优先级,让最可能成功的地址先被尝试。RFC 5245 给出经验权重:类型偏好 host=126、srflx=100、relay=0;同类型若有多条网卡,再用本地偏好细分;最后用组件号微调(RTP 是组件 1,RTCP 是组件 2)。三者相乘叠加,得出最终优先级。

于是每个人的名片都厚了起来,但每一行地址都不是随手写的——优先级就是试拨顺序。这也是工程师们常说“优先走 P2P、TURN 只做最后退路”的原因:能直连就不绕路,绕路也要选最短的那条。

priority=224×type_preference+28×local_preference+(256−component_id)\displaystyle \text{priority} = 2^{24} \times \text{type\_preference} + 2^{8} \times \text{local\_preference} + (256 - \text{component\_id})
优先级越高,连通性检查时越先尝试。直观理解:办公室座机的重量级远高于快递柜,所以要先拨座机,拨不通才去快递柜。
  1. 类型偏好三类候选的基础权重,host 最高、relay 最低,决定排序的第一位。
    type_preference∈{126,100,0}\displaystyle \text{type\_preference} \in \{126, 100, 0\}
  2. 本地偏好同类型多个候选时的二级细分权重,多网卡场景下用来区分“先试哪张卡”。
    local_preference=65535 或 32767\displaystyle \text{local\_preference} = 65535 \text{ 或 } 32767
  3. 组件号修正组件号小的优先,保证 RTP 媒体流排在 RTCP 控制流之前。
    256−component_id\displaystyle 256 - \text{component\_id}

连通性检查

两边都拿到名片后,接下来是“秘书”的工作:把两张名单交叉配对,然后按顺序试拨。假设 Alice 有 3 个候选、Bob 有 2 个,两两组合最多得到 6 个“候选对”(candidate pair)。每个候选对都是一种可能的通路,ICE 会为每个候选对计算优先级,然后从高到低逐个探测。

探测的方式是发送 STUN Binding 请求:向对端候选地址发一个“你在吗”的探测包,若在规定时间内收到响应,就说明这条链路真实可用——就像秘书拿起话筒拨号,听到“嘟——”才确认这个号码是真的。检查过程中有两个角色:controlling(控制方)和 controlled(被控制方)。控制方负责做最终决策,决定选哪条路;被控制方只配合回应。若双方都以为自己是控制方,就用一个随机 tie-breaker 数字决出胜负,保证只有唯一控制方。

候选对的优先级不是简单相加,而是“小者优先”:公式中权重最大的项是双方候选优先级里较小的那个。为什么要这样设计?因为整条链路的可用性取决于“最弱的一环”——Alice 的 host 地址再快,Bob 那边只有 relay 地址,那这趟也只能走中继。检查全部就绪后,控制方执行提名(nomination):激进模式下第一条连通的路直接当选;常规模式则等所有候选对检查完,再选最优的一条。

所以一次通话看起来是“秒连”,背后其实是秘书们拿着试拨清单,把每对地址都试了一遍。连通性检查就是这套“试拨电话”——通了记下,不通翻页,直到找到那条真正能走的路。

pair_priority=232×min⁡(G,D)+2×max⁡(G,D)+(G>D)\displaystyle \text{pair\_priority} = 2^{32} \times \min(G, D) + 2 \times \max(G, D) + (G > D)
其中 G 是控制方候选的优先级,D 是被控制方候选的优先级。权重最大的项是 min(G,D),即“短板决定木桶容量”。
  1. 短板优先以双方优先级中的较小值为最大权重,体现“最弱一环决定链路可用性”。
    232×min⁡(G,D)\displaystyle 2^{32} \times \min(G, D)
  2. 长板次之较大值作为二级权重,在短板相同时,更优秀的那一方获得更高排序。
    2×max⁡(G,D)\displaystyle 2 \times \max(G, D)
  3. 决胜位当 G 大于 D 时加 1,确保平局时控制方略占优势,避免排序歧义。
    +(G>D)\displaystyle + (G > D)

失败重试机制

电话会占线、会空号、会中途掉线,地址也一样。ICE 的试拨不是拨一次就完事,而是带超时、带重试、带降级预案的。

每个连通性检查都有一个 RTO(重传超时)期限:初始值取 500 毫秒和 2 倍 RTT 中的较大者。若超时未收到响应,检查方会重传,并按指数退避拉长等待时间,直到 30 秒上限。重传达到次数上限仍无响应,这个候选对就被标记为失败,转去尝试下一对。这就像电话拨不通时你不会干等,而是隔一会儿再拨一次,越等越久,最后放弃换下一个号码。

当 host 和 srflx 候选全部失败时,降级顺序就“倒过来走”——最终落回 relay 中继候选。TURN 中继虽然有额外延迟、还要占用服务器带宽,但它对对称 NAT 和严格防火墙几乎百分百有效,是真正的“最后一道保险”。即使所有候选都失败,前端还可以触发 ICE Restart:重新收集候选、重新发起 Offer/Answer,从头再来一遍,相当于“换个手机号再打一次”。

失败不可怕,可怕的是没有预案。重试与降级机制让通话建立过程像走迷宫:先试直线,被挡就绕道;实在绕不过去,就从邮局的公共通道走——无论哪条路,最终目标是让两边顺利接上头。

tn=min⁡(t0×2n,  30 s),t0=max⁡(500 ms,  2×RTT)\displaystyle t_{n} = \min \left( t_{0} \times 2^{n}, \; 30\,\text{s} \right), \quad t_{0} = \max(500\,\text{ms}, \; 2 \times RTT)
第 n 次重试的等待时间从初始值开始翻倍,但封顶 30 秒,防止无限等待拖垮用户体验。
  1. 初始超时以 500 毫秒为下限、2 倍 RTT 为基准,避免在慢网络上过早放弃。
    t0=max⁡(500 ms,  2×RTT)\displaystyle t_{0} = \max(500\,\text{ms}, \; 2 \times RTT)
  2. 指数退避每次失败等待翻倍,避免大量重试同时涌向网络造成雪崩。
    tn=t0×2n\displaystyle t_{n} = t_{0} \times 2^{n}
  3. 最大上限等待时间封顶 30 秒,超时后彻底放弃当前候选对。
    tn≤30 s\displaystyle t_{n} \leq 30\,\text{s}

生产部署路径

演示环境里一台电脑就能跑通信令服务器,但生产环境要考虑的是:邮局够不够用?高峰期会不会排队?中转站带宽扛不扛得住?这就是从概念验证(POC)走向生产部署时必须回答的问题。

部署前先做容量规划。信令服务器处理的是小消息,瓶颈在连接数和消息吞吐量;TURN 服务器的瓶颈则在带宽。经验估算:一路 720p 视频经 TURN 转发约需 1.5-2 Mbps,假设单机带宽 1 Gbps,理论并发约 500 路。信令节点虽不碰媒体,但要按“在线用户数 × 并发率”预留连接数,并留出 2-3 倍冗余应对突发。

拓扑上,信令节点要做水平扩展,前面挂负载均衡;TURN 服务器按地域就近部署,并配置多节点 failover。上线后必须盯好的监控指标包括:在线连接数、信令消息延迟、ICE 检查失败率、TURN 中继占用率、端到端建连耗时(p95)。这些指标能直接回答“用户为什么打不通电话”——是信令慢了、NAT 穿透失败,还是 TURN 满了。

从概念验证到生产,本质是把“能通”升级成“总能通”。邮局多了、线路备了、还能实时看见哪条街拥堵,通话体验才谈得上稳定——这就是 POC 与生产之间那条看不见的鸿沟。

C=⌊BserverBcall⌋,N=⌈U×PC⌉\displaystyle C = \left\lfloor \frac{B_{server}}{B_{call}} \right\rfloor, \qquad N = \left\lceil \frac{U \times P}{C} \right\rceil
C 是单台 TURN 服务器可承载的并发通话数,N 是所需服务器数量。带宽越宽、每路码率越低,能服务的用户就越多。
  1. 单节点容量服务器总带宽除以每路通话平均码率,向下取整得到并发上限。
    C=⌊BserverBcall⌋\displaystyle C = \left\lfloor \frac{B_{server}}{B_{call}} \right\rfloor
  2. 并发用户数注册用户总数乘以同时通话比例,得到峰值并发需求。
    U×P\displaystyle U \times P
  3. 节点数量并发需求除以单节点容量,向上取整并加冗余。
    N=⌈U×PC⌉\displaystyle N = \left\lceil \frac{U \times P}{C} \right\rceil

工程实践建议

机制都懂了,接下来是“用得好”这门手艺。工程实践里,同样一套信令和 ICE,不同的选型与配置,体验可以差出数倍。

信令选型上,WebSocket 依然是主流,胜在生态成熟、全双工、低延迟;若对首包延迟和头部开销更敏感,可以评估 WebTransport。协议设计从第一天就要带版本号与能力协商字段,避免前后端迭代时互相不认识。安全方面:信令通道必须走 TLS 加密,加入房间要 token 鉴权,SDP 中不要暴露多余的内网 IP,防止信息泄露。

性能优化上,优先开启 Trickle ICE——候选边收集边发送,不用等全部就绪,通常能缩短 30%-50% 的建连时间;服务端如果是 SFU/MCU 星型转发架构,可用 ICE-lite 模式减少交互开销;对高频拨打对象可以做“预连接”,在后台提前建立 ICE 会话。排查问题时打开 chrome://webrtc-internals 看 stats:若发现大量通话依赖 relay 候选,说明 NAT 穿透配置待优化,应检查 STUN 服务器连通性与防火墙策略。

工程实践的金标准是“让用户无感”。复杂留给系统,流畅留给用户——所有优化落回同一个目标:无论网络多复杂,让通话像面对面聊天一样自然。

Ltotal=Lcapture+Lencode+Lnetwork+Ljitter+Lplayout≤400 ms\displaystyle L_{total} = L_{capture} + L_{encode} + L_{network} + L_{jitter} + L_{playout} \leq 400\,\text{ms}
端到端音频延迟预算约 400 毫秒,超过这个值人耳就能明显感到“说着说着一顿一顿”。ICE 选对路能压缩网络段延迟,而选错路(如被迫走 TURN)会显著拉高这一项。
  1. 采集与编码麦克风/摄像头的采集时间与编码器打包时间,通常是固定开销。
    Lcapture+Lencode\displaystyle L_{capture} + L_{encode}
  2. 网络与抖动P2P 直连时最小,走 TURN 中继时多一跳;抖动缓冲为平滑播放额外增加等待。
    Lnetwork+Ljitter\displaystyle L_{network} + L_{jitter}
  3. 缓冲播放接收端抖动缓冲的等待时间,是延迟预算的最后一块拼图。
    +Lplayout\displaystyle + L_{playout}

AI 应用场景

在线面试与互动课堂

阶段:实时音视频底层链路搭建

解决的问题:面试双方往往身处企业办公网,NAT 类型复杂、防火墙严格;若所有媒体都走服务器转发,带宽成本高且时延感人。信令服务器 + ICE 组合让大多数流量走 P2P 直连,TURN 只兜底极小比例。

具体案例:某在线面试平台使用 WebSocket 信令服务器交换 SDP 与 Trickle 候选,使 95% 的通话建立 P2P 直连;剩余 5% 对称 NAT 场景自动切换 TURN 中继。同时 AI 实时字幕通过信令通道带外传输字幕文本而非音视频,字幕延迟被压缩到 200 毫秒以内。

AI 数字人实时语音对话

阶段:端侧交互与云端大模型实时链路

解决的问题:数字人应用需要低延迟地把用户语音上行到云端大模型,再把生成的语音下行回传到端侧;用 WebSocket 传音频分片会有乱序与队头阻塞,需要 UDP 媒体通道。

具体案例:某 AI 陪伴应用让用户与数字人视频通话,接入层用信令服务器完成“用户 ↔ AI 节点”的候选配对,AI 节点侧使用 ICE-lite 简化交互;媒体走 P2P 后的往返延迟从 WebSocket 方案的 400 毫秒降到 120 毫秒,AI 回复的“思考延音”大幅缩短。

远程医疗会诊与网络诊断

阶段:会话质量监测与智能调优

解决的问题:医疗会诊对清晰度和抖动要求极高,传统方案在弱网下“一刀切降码率”会牺牲影像细节;需要根据 ICE 候选类型和丢包统计做精细化诊断与自适应。

具体案例:会诊平台利用 ICE 候选分布判断网络类型——当 srflx 反射候选检查长期失败时,系统自动切换到 TURN 中继并同步调低帧率;AI 辅助分析 stats 面板,生成“建议开通 UDP 端口 / 升级企业防火墙策略”的可执行报告,将一次会诊的建连失败率从 8% 降至 1% 以下。

Python 演示

python103 行
"""信令服务器与 ICE 候选收集简化模拟"""import random  class ICECandidate:    """一个 ICE 候选地址(名片上的一个联系地址)"""     def __init__(self, ip, port, cand_type, component_id=1, local_pref=None):        self.ip = ip        self.port = port        self.cand_type = cand_type        self.component_id = component_id        self.local_pref = local_pref        self.priority = self.calc_priority()     def calc_priority(self):        type_pref = {"host": 126, "srflx": 100, "relay": 0}[self.cand_type]        if self.local_pref is None:            self.local_pref = 65535 if self.cand_type == "host" else 32767        return (2 ** 24) * type_pref + (2 ** 8) * self.local_pref + (256 - self.component_id)     def __repr__(self):        return "%s(%s:%d)" % (self.cand_type, self.ip, self.port)  class SignalingServer:    """邮局: 只转发控制消息, 不碰媒体数据"""     def __init__(self):        self.log = []     def route(self, msg):        self.log.append(msg)        return msg  class ICEAgent:    """每个对端都有一个 ICE 秘书: 收集, 配对, 试拨"""     def __init__(self, name, candidates):        self.name = name        self.candidates = sorted(candidates, key=lambda c: c.priority, reverse=True)        self.role = "controlling"        self.selected_pair = None     def make_pairs(self, remote_candidates):        pairs = []        for local in self.candidates:            for remote in remote_candidates:                g = local.priority                d = remote.priority                pair_prio = (2 ** 32) * min(g, d) + 2 * max(g, d) + (1 if g > d else 0)                pairs.append((pair_prio, local, remote))        pairs.sort(reverse=True)        return [(local, remote) for _, local, remote in pairs]     def connectivity_check(self, pairs):        for local, remote in pairs:            if local.cand_type == "relay" or remote.cand_type == "relay":                ok = True            elif local.cand_type == "host" and remote.cand_type == "host":                ok = True            else:                ok = random.random() > 0.3            if ok:                self.selected_pair = (local, remote)                return local, remote        return None  def main():    random.seed(42)    alice = ICEAgent("Alice", [        ICECandidate("192.168.1.10", 50001, "host"),        ICECandidate("203.0.113.5", 50002, "srflx"),        ICECandidate("198.51.100.7", 3478, "relay"),    ])    bob = ICEAgent("Bob", [        ICECandidate("10.0.0.2", 50011, "host"),        ICECandidate("198.51.100.7", 3478, "relay"),    ])    server = SignalingServer()     # 阶段一: 交换 SDP 名片    server.route({"from": "Alice", "to": "Bob", "sdp": "offer"})    server.route({"from": "Bob", "to": "Alice", "sdp": "answer"})     # 阶段二: Trickle 收集候选, 全部经信令服务器转发    for cand in alice.candidates + bob.candidates:        server.route({"from": "?", "to": "?", "candidate": str(cand)})     # 阶段三: 配对 + 连通性检查    pairs = alice.make_pairs(bob.candidates)    print("候选配对数量:", len(pairs))    winner = alice.connectivity_check(pairs)    if winner:        print("连通成功:", winner[0], "<->", winner[1])    else:        print("全部失败, 需要 TURN 中继兜底")  if __name__ == "__main__":    main()
目的:用约百行 Python 模拟 WebRTC 建连流程——双方通过“邮局”交换 SDP 与 ICE 候选,ICEAgent 按优先级配对并逐个试拨,最终选出可用的直连路径。
  1. class ICECandidate:定义“名片”模型:一个候选就是一条可被联系的通路,包含地址、端口和类型。
  2. type_pref = {"host": 126, "srflx": 100, "relay": 0}[self.cand_type]类型偏好直接映射为公式权重,host 最高、relay 最低。
  3. server.route({"from": "Alice", "to": "Bob", "sdp": "offer"})信令服务器只转发控制消息,媒体数据完全不经手。
  4. for cand in alice.candidates + bob.candidates:Trickle 思想:候选不等齐,先收集到就先发给对方。
  5. pairs.sort(reverse=True)按候选对优先级从高到低排序,决定试拨顺序。
  6. if local.cand_type == "relay" or remote.cand_type == "relay":中继候选永远可用,是最后的兜底通道。
  7. random.seed(42)固定随机种子,让“反射候选 30% 概率失败”的模拟结果可复现。

常见误区

误区我一直以为信令服务器就像视频会议的中转中心,所有画面和声音都要从它这儿过一遍,所以带宽要按视频码率来算。

正解信令服务器只交换“名片”——SDP 会话描述、ICE 候选、控制指令,媒体流建立后通常走 P2P 直连,根本不经过服务器。邮局帮你递名片,不会帮你们俩站在后面聊天。带宽需求上,信令关心的是连接数和消息吞吐量,而不是媒体码率。

为何常见:许多架构图把服务器画在两端中间,箭头指向又粗又密,让人误以为它在转发媒体,其实只有 TURN 中继才做转发。

误区ICE 不是用来穿透 NAT 的吗?那两边都有公网 IP,直接连不就行了,何必还要收集候选。

正解公网 IP 不等于一定能直连。中间可能隔着防火墙,只放行特定端口和协议;也可能运营商做了端口限制。ICE 是“多条腿走路”的组合方案,公网 IP 只是 host 候选之一,仍然要经过候选配对和连通性检查来验证这条路真的通。

为何常见:把 ICE 简单等同于 NAT 穿透,忽略了防火墙、端口过滤等同样影响连通性的因素。

误区只要集成了 WebRTC 和 ICE,任何网络环境下都能直连成功,TURN 只是可选项,装不装无所谓。

正解对称 NAT 和部分企业防火墙会直接让 STUN 反射地址失效——你在内网发出的端口和外部看到的映射端口不同,每次请求都不一样。这种情况下 ICE 会试完所有候选对后失败。TURN 中继是真正的“兜底保险”,虽然绕路、费带宽,但保证通话能建立。

为何常见:ICE 全称带 Connectivity Establishment,名字听上去像“必定建立”,容易让人忽略它只是尽力而为。

误区流程上应该是先把 host、srflx、relay 所有候选都收集齐,再发 Offer 给对方,不然后面新发现的地址就白收了。

正解Trickle ICE 允许边收集边通知——先发主机候选,STUN/TURN 的结果陆续通过信令通道发补充消息,对端实时把新候选加进候选池。这就像先把手机号发过去聊起来,座机号想起来再补发,不用等名片印好才出门。

为何常见:早期 RFC 5245 默认是全量收集模式,不少老教程仍按旧流程讲解,没跟上 Trickle 的演进。

误区信令服务器不就是个 WebSocket 中转站嘛,能收发消息、能把 A 的消息转给 B,就算完工了。

正解生产级信令远不止“转发”:要管理会话状态机(谁在哪个房间、Offer/Answer 是否乱序)、校验消息归属(ICE 候选必须关联到正确的会话和房间)、处理断线重连与心跳超时,还要做鉴权、版本兼容、消息节流。Demo 里的 echo 服务器掩盖了这些真实复杂度。

为何常见:教程 demo 往往只演示“收到消息就转发”,让人误以为状态管理和异常处理都是多余的。

面试题

Q1. WebRTC 中信令服务器的核心职责是什么?

单选题 · easy

  • A.转发音视频媒体数据
  • B.交换会话描述与候选信息← 正确答案
  • C.负责音视频编解码处理
  • D.存储全部通话记录数据

答案:B。信令服务器负责交换 SDP 会话描述和 ICE 候选等元数据,像邮局递名片;媒体数据走 P2P 直连,不经由信令服务器。选 A 是把信令服务器误当成媒体中转,C 是编解码器的工作,D 与信令职责无关。

Q2. 下列哪类 ICE 候选的优先级最高?

单选题 · easy

  • A.host 主机候选← 正确答案
  • B.srflx 反射候选
  • C.relay 中继候选
  • D.三类候选完全一致

答案:A。ICE 优先级按“越直接越优先”设计,host 候选走本机网卡直连,权重 126 最高;srflx 反射候选权重 100 次之;relay 中继候选权重 0 最低,只作兜底。D 明显错误,三者权重完全不同。

Q3. STUN 服务器的主要作用是什么?

单选题 · mid

  • A.中继转发媒体流量
  • B.发现公网映射地址← 正确答案
  • C.管理会话的 SDP 状态
  • D.对通话内容加密保护

答案:B。STUN 通过 Binding 请求让客户端知道自己在外网被映射到的 IP 和端口,即生成 srflx 反射候选,相当于问收发室“外人看到的我是什么地址”。A 是 TURN 的职责,C 是信令服务器的职责,D 是 DTLS-SRTP 的职责。

Q4. 面对对称 NAT 导致的直连失败,最稳妥的兜底方案是?

单选题 · mid

  • A.重新收集主机候选
  • B.关闭 ICE 穿透功能
  • C.使用 TURN 中继候选← 正确答案
  • D.改用 HTTP 长轮询

答案:C。对称 NAT 下 STUN 反射地址每次映射都不同,直连基本无解。TURN 中继候选让媒体经服务器接力转发,绕过 NAT 限制,是 RFC 推荐的最后兜底。重收主机候选解决不了 NAT 映射问题,关闭 ICE 会直接断连。

Q5. ICE 候选对优先级公式中起决定性作用的分量是?

单选题 · hard

  • A.较小一方的优先级← 正确答案
  • B.较大一方的优先级
  • C.组件编号本身大小
  • D.双方约定的随机值

答案:A。候选对优先级公式中,权重最大项是 min(G, D),即双方优先级中的较小值——整条链路的可用性由“最弱一环”决定。较大值只是二级权重,组件号是微调,tie-breaker 只用于角色判定,与优先级无关。

Q6. 关于 Trickle ICE,下列说法正确的是?

多选题 · mid

  • A.候选边收集边发送← 正确答案
  • B.缩短连接建立时间← 正确答案
  • C.必须等候选全部齐
  • D.对端动态加入候选池← 正确答案

答案:ABD。Trickle ICE 的核心是“不等齐就出发”:先发已收集的候选,后续候选通过信令补充,对端动态加入候选池,从而让建连时间缩短 30%-50%。C 说的是旧的全量收集模式,与 Trickle 相反。

Q7. 连通性检查主要依赖哪类协议报文?

单选题 · mid

  • A.发 HTTP 请求报文
  • B.发 STUN 探测报文← 正确答案
  • C.发 DNS 查询报文
  • D.发 ICMP 探测报文

答案:B。ICE 连通性检查复用 STUN Binding 请求——向对端候选发探测包并等待响应,本质上是“试拨电话”。HTTP 基于 TCP 不适用于 UDP 媒体路径探测,DNS 用于域名解析,ICMP 常被防火墙屏蔽且与媒体路径不一致。

Q8. 生产环境部署信令与 TURN 服务时需考虑?

多选题 · hard

  • A.信令节点水平扩容← 正确答案
  • B.TURN 带宽容量估算← 正确答案
  • C.媒体传输免设超时
  • D.ICE 失败率监控告警← 正确答案

答案:ABD。生产部署要按容量公式规划信令节点数量、按并发码率估算 TURN 带宽,并持续监控 ICE 失败率与 TURN 占用率。“媒体传输免设超时”违背重试机制设计,连通性检查必须有 RTO 与重传上限。

Q9. ICE 候选降级尝试的正确顺序是?

单选题 · easy

  • A.中继反射主机依次尝试
  • B.主机反射中继依次尝试← 正确答案
  • C.反射中继主机依次尝试
  • D.按随机排列一一尝试

答案:B。候选尝试顺序与优先级一致:先 host 主机候选(最直接),再 srflx 反射候选(NAT 映射),最后 relay 中继候选(兜底)。随机排列会破坏优先级设计,导致大量不必要的绕路。

Q10. WebRTC 中“控制方”的 tie-breaker 主要用于?

单选题 · extreme

  • A.决定谁先发送媒体流
  • B.角色冲突时裁定控制方← 正确答案
  • C.提高本端候选优先级
  • D.决定中继服务器选址

答案:B。当双方都认为自己是控制方、角色冲突时,双方交换各自随机生成的 tie-breaker(64 位随机数),较大者胜出为唯一控制方,避免提名决策混乱。媒体发送顺序由协商决定,tie-breaker 不涉及优先级或 TURN 选址。