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 收到数据时被触发。
-
解析:将接收到的 buf 解析为 StunMessage 对象。
-
验证:检查消息格式是否合法。
-
路由根据 STUN 消息的类型(Method),分发到具体的处理函数:
• Binding Request -> OnBindingRequest
• Allocate Request -> OnAllocateRequest (通常用于 TURN,但 STUN 服务器可能返回错误或不支持)
• Shared Secret Request -> OnSharedSecretRequest (旧式认证机制,现已很少用)
• Send Request -> OnSendRequest (旧式机制)
3.2 处理Binding请求(OnBindingRequest)
这是最核心、最常用的功能。
-
获取源地址:从参数 addr 中获取客户端的源 IP 和端口(这是经过 NAT 转换后的公网地址)。
-
构建响应:调用 GetStunBindResponse。
• 创建一个 StunMessage 响应。
• 添加 XOR-MAPPED-ADDRESS 属性:将 addr 填入。使用 XOR 是为了防止某些 NAT 设备修改 STUN 载荷中的 IP 地址。
• 复制事务 ID(Transaction ID)以便客户端匹配请求和响应。
- 发送:调用 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 穿透的关键。
- 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 连接建立过程中的第一个里程碑。
-
客户端向 StunServer 发送 Binding Request。
-
StunServer 回复:"你的公网地址是 X.X.X.X:Port"。
-
客户端将这个地址作为 Server Reflexive Candidate (srflx) 加入 ICE 候选者列表。
-
如果没有这个类提供的信息,位于 NAT 后的客户端将无法告知对端如何连接自己,P2P 直连也就无从谈起。