You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:48:50