Django+aiortc搭建浏览器-服务端WebRTC连接报WinError 10051错误
问题根因
WinError 10051对应套接字网络不可达错误,所有ICE候选对连通失败由三个直接问题导致:
- 初始化
RTCPeerConnection时未配置STUN/TURN服务器,服务端仅能收集到172.18段内网地址候选,客户端上报的109.120段公网候选、192.168段内网候选和服务端不在同一广播域,无中继的情况下NAT穿透必然失败。 - 信令逻辑缺失:仅实现了客户端到服务端的ICE候选转发,没有把aiortc本地生成的ICE候选通过信令发给客户端,客户端无服务端候选可测,连通性检查不可能完成。
- 代码存在显性bug:
RTCRoom.receive方法调用了json.loads但未导入json模块,会直接触发运行时异常中断信令处理;同时ICE候选添加未做时序控制,在远端SDP未设置完成时提前加候选会触发内部错误。
修复步骤
1. 补全缺失依赖
在consumers.py头部补上缺失的导入:
import json
2. 为PeerConnection配置STUN/TURN服务
公网部署场景至少配置STUN服务器获取公网候选,跨内网场景必须搭配TURN中继保证连通性,替换RTCPeer类中原有PeerConnection初始化逻辑:
# 替换原代码中 self.peer_connection = RTCPeerConnection() 部分 config = RTCConfiguration( iceServers=[ RTCIceServer(urls="stun:stun.l.google.com:19302"), # 跨内网场景补充自有TURN服务配置 # RTCIceServer(urls="turn:你的TURN服务地址", username="账号", credential="密码") ] ) self.peer_connection = RTCPeerConnection(configuration=config)
3. 补全服务端ICE候选上报逻辑
在RTCPeer类的PeerConnection初始化完成后,绑定icecandidate事件回调,将本地生成的候选通过信令发送给对应客户端:
@self.peer_connection.on("icecandidate") async def on_icecandidate(candidate): if candidate: await self.send({ 'receiver': self.peer_username, 'candidate': { 'candidate': candidate.to_sdp(), 'sdpMid': candidate.sdpMid, 'sdpMLineIndex': candidate.sdpMLineIndex } })
4. 修复ICE候选添加时序问题
WebRTC规范要求必须完成setRemoteDescription后才能添加远端ICE候选,需要新增候选缓存队列处理提前到达的候选:
首先在RTCPeer.__init__方法中新增状态变量:
self.pending_ice_candidates = [] self.remote_description_set = False
修改handle_message中的SDP处理逻辑,设置完远端描述后批量处理缓存候选:
if description.type == "offer": await self.peer_connection.setRemoteDescription(description) self.remote_description_set = True # 批量添加缓存的提前到达候选 for cand in self.pending_ice_candidates: await self.peer_connection.addIceCandidate(cand) self.pending_ice_candidates.clear() await self.peer_connection.setLocalDescription(await self.peer_connection.createAnswer()) await self.send({ 'receiver': self.peer_username, 'description': { 'type': self.peer_connection.localDescription.type, 'sdp' : self.peer_connection.localDescription.sdp, } })
修改候选处理分支,远端SDP未就绪时先缓存候选:
elif candidate: rtc_ice_candidate = candidate_from_sdp(candidate.get('candidate').split(":", 1)[1]) rtc_ice_candidate.sdpMid = candidate.get('sdpMid') rtc_ice_candidate.sdpMLineIndex = candidate.get('sdpMLineIndex') if not self.remote_description_set: self.pending_ice_candidates.append(rtc_ice_candidate) else: await self.peer_connection.addIceCandidate(rtc_ice_candidate)
5. 部署侧配置检查
如果服务端部署在云服务器/容器环境,需要放开UDP端口的入站规则(aiortc默认使用随机UDP端口传输媒体流),Docker部署优先使用host网络模式避免端口映射导致的连通问题。
日志中俄文报错原意为「网络未连接时尝试执行套接字操作」,本质是服务端往不可达的客户端候选地址发包触发的路由错误,按上述步骤补全信令逻辑、配置穿透服务后即可解决。
内容的提问来源于stack exchange,提问作者Artem Ermakov
相关产品推荐
相关产品推荐

