使用STUN获取外网IP端口后,UDP P2P通信失败求助
UDP P2P通信打洞失败问题
我尝试通过UDP实现P2P通信,借助pystun3获取到外网IP和端口,但客户端B使用该IP和端口发送数据时,始终无法到达客户端A。我清楚不能关闭socket,否则NAT会重新分配端口,但即使保持socket开启,客户端A仍无法接收数据。
代码片段
客户端A(查询外网IP和端口)
import socket from stun import get_nat_type # 创建socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(20) s.setsockopt(socket.SOL_SOCKET, SO_REUSEADDR, 1) s.bind(("0.0.0.0",15000)) # 查询STUN服务器获取外网IP和端口 nat_type, nat = get_nat_type(s, "0.0.0.0", 15000, stun_host=None, stun_port=3478) external_ip = nat['ExternalIP'] external_port = nat['ExternalPort'] # 输出STUN数据并监听客户端B数据 print("Punch hole: ('{0}',{1})".format(external_ip, external_port)) print("listening port for incoming data") print(s.recvfrom(4096)[0])
客户端B(发送数据)
from socket import * s = socket(AF_INET, SOCK_DGRAM) s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) s.sendto(b"hey!", ('<External IP of Client A>', 11224))
问题排查与解决办法
- 端口不匹配:客户端A绑定本地端口15000,但客户端B发送的目标端口是11224,完全不对应。必须使用STUN返回的
external_port作为客户端B的目标端口,而非手动填写的11224。 - NAT类型限制:如果是对称型NAT,仅靠STUN获取的端口无法直接打洞——对称NAT会给每个不同目标IP分配独立的外网端口。这种情况需要双方同时向对方发起连接请求,触发NAT建立双向映射,或者借助第三方中继服务器中转数据。
- 防火墙拦截:检查客户端A的本地防火墙设置,确保允许UDP端口15000的入站连接,避免数据包被拦截。
- Socket状态保持:
get_nat_type调用时会使用客户端A的socket发送STUN请求,NAT映射的是该socket的会话。必须保持这个socket持续开启,且只能用它来接收数据,不能重新创建新socket。 - 冗余设置移除:客户端B发送单播数据,不需要设置
SO_BROADCAST选项,移除该设置可避免潜在异常。
修正后的代码示例
客户端A
import socket from stun import get_nat_type # 创建UDP socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(20) s.setsockopt(socket.SOL_SOCKET, SO_REUSEADDR, 1) s.bind(("0.0.0.0", 15000)) # 查询STUN获取外网地址 nat_type, nat = get_nat_type(s, "0.0.0.0", 15000, stun_host=None, stun_port=3478) external_ip = nat['ExternalIP'] external_port = nat['ExternalPort'] print(f"打洞目标地址: ('{external_ip}', {external_port})") print("等待客户端B数据...") data, addr = s.recvfrom(4096) print(f"收到来自{addr}的消息: {data.decode()}")
客户端B
from socket import * s = socket(AF_INET, SOCK_DGRAM) # 使用客户端A返回的外网IP和端口 s.sendto(b"hey!", ('客户端A实际外网IP', 客户端A STUN返回的外网端口))
内容的提问来源于stack exchange,提问作者Felipe
相关产品推荐
相关产品推荐

