webrtc StunServer源码介绍

StunServer 是 WebRTC 中实现 STUN (Session Traversal Utilities for NAT) 协议服务器端逻辑的核心类。实现了 RFC 5389/8489 的核心交互逻辑,是 ICE 框架不可或缺的基础设施。

它的主要职责是监听 UDP 端口,接收客户端发出的 STUN 请求,解析消息,并根据请求类型生成相应的响应(主要是返回客户端的公网映射地址),从而帮助位于 NAT 后面的客户端发现其公共 IP 和端口。

一、角色功能

• NAT 穿透助手:STUN 协议本身不中继数据(那是 TURN 的工作),它只负责"探测"。StunServer 告诉客户端:"我从这个 IP 和端口收到了你的包",客户端由此推断出 NAT 为其分配的公网地址。

• 轻量级服务:与 TurnServer 不同,StunServer 是无状态的(Stateless)。它不需要维护会话、权限或分配中继端口,处理完一个请求即可忘记,因此性能极高,并发能力强。

二、成员介绍

1. socket (std::unique_ptr<rtc::AsyncUDPSocket>):

cpp 复制代码
class StunServer : public sigslot::has_slots<> {
 public:
  // Creates a STUN server, which will listen on the given socket.
  explicit StunServer(rtc::AsyncUDPSocket* socket);
  // Removes the STUN server from the socket and deletes the socket.
  ~StunServer() override;

 private:
  std::unique_ptr<rtc::AsyncUDPSocket> socket_;
};

• 底层 UDP Socket,绑定在特定端口(默认 3478)。

• 负责接收原始字节流并发送响应字节流。

• 在构造函数中传入,析构时销毁。

三、主要工作流程

3.1 接收数据包

这是入口函数,当 Socket 收到数据时被触发。

  1. 解析:将接收到的 buf 解析为 StunMessage 对象。

  2. 验证:检查消息格式是否合法。

  3. 路由根据 STUN 消息的类型(Method),分发到具体的处理函数:

• Binding Request -> OnBindingRequest

• Allocate Request -> OnAllocateRequest (通常用于 TURN,但 STUN 服务器可能返回错误或不支持)

• Shared Secret Request -> OnSharedSecretRequest (旧式认证机制,现已很少用)

• Send Request -> OnSendRequest (旧式机制)

3.2 处理Binding请求(OnBindingRequest)

这是最核心、最常用的功能。

  1. 获取源地址:从参数 addr 中获取客户端的源 IP 和端口(这是经过 NAT 转换后的公网地址)。

  2. 构建响应:调用 GetStunBindResponse。

• 创建一个 StunMessage 响应。

• 添加 XOR-MAPPED-ADDRESS 属性:将 addr 填入。使用 XOR 是为了防止某些 NAT 设备修改 STUN 载荷中的 IP 地址。

• 复制事务 ID(Transaction ID)以便客户端匹配请求和响应。

  1. 发送:调用 SendResponse 将包发回给 addr。

3.3 其它请求

• OnAllocateRequest: STUN 协议本身不支持分配中继资源。如果收到此请求,标准的 STUN 服务器通常会返回错误码 400 (Bad Request) 或 500 (Server Error),或者如果它是一个混合了 TURN 功能的服务器,可能会转发给 TURN 逻辑(但在纯 StunServer 实现中通常是不支持的或返回错误)。

• OnSharedSecretRequest / OnSendRequest: 这些属于旧的 STUN 规范(RFC 3489),在现代 WebRTC (RFC 5389/8489) 中已废弃。实现中通常返回错误或忽略。

3.4 发生响应(SendResponse / SendErrorResponse)

• 序列化:将 StunMessage 对象序列化为二进制字节流。

• 计算完整性:如果需要,添加 MESSAGE-INTEGRITY 或 FINGERPRINT 属性。

• UDP 发送:通过 socket_->SendTo 将数据发回给客户端的地址。

3.5 辅助方法

1。 GetStunBindResponse:

• 专门用于构造 Binding 响应的工具函数。

• 确保正确设置 XOR-MAPPED-ADDRESS,这是 NAT 穿透的关键。

  1. SendErrorResponse:

• 构造包含 ERROR-CODE 属性的 STUN 错误响应。

• 常见错误:400 (Bad Request), 401 (Unauthorized - 如果启用了认证), 500 (Server Error).

四、与TURNservice的区别

|------|----------------------------|--------------------------------|
| 特性 | StunServer | TurnServer |
| 主要功能 | 发现公网 IP/Port (NAT Mapping) | 中继媒体数据 (Relaying) |
| 状态 | 无状态 (Stateless) | 有状态 (Stateful, 维护 Allocation) |
| 资源消耗 | 极低 (仅 CPU 解析/打包) | 高 (带宽转发, Socket 维护) |
| 核心响应 | XOR-MAPPED-ADDRESS | RELAYED-ADDRESS, 数据转发 |
| 安全性 | 简单 (可选认证) | 复杂 (Permission, Channel, Auth) |
| 用途 | ICE 候选者收集阶段 | ICE 失败后的 fallback |

五、总结

StunServer 是 WebRTC P2P 连接建立过程中的第一个里程碑。

  1. 客户端向 StunServer 发送 Binding Request。

  2. StunServer 回复:"你的公网地址是 X.X.X.X:Port"。

  3. 客户端将这个地址作为 Server Reflexive Candidate (srflx) 加入 ICE 候选者列表。

  4. 如果没有这个类提供的信息,位于 NAT 后的客户端将无法告知对端如何连接自己,P2P 直连也就无从谈起。

相关推荐
换个昵称都难2 小时前
webrtc RTC_P2P源码解析
asp.net·webrtc·p2p
数据知道1 天前
指纹浏览器:DNS 泄漏防范与 WebRTC 本地 IP 屏蔽的底层实现
爬虫·网络协议·tcp/ip·安全·webrtc·数据采集·指纹浏览器
换个昵称都难2 天前
webrtc源码解析概要介绍
webrtc
换个昵称都难2 天前
WebRTC 完整调用流程(前端纯 JS 实现,最简可运行)
webrtc
换个昵称都难3 天前
webrtc 拥塞控制GCC 和PCC
webrtc
Cxiaomu3 天前
React接入WebRTC实时视频实践
react.js·音视频·webrtc
AndyHuang19763 天前
WebRTC 强制 Relay 模式下 TCP 重连失败深度排查与优化实战
webrtc
换个昵称都难3 天前
webrtc pacing 平滑发包模块
webrtc
换个昵称都难3 天前
webrtc 音频混音介绍
音视频·webrtc