你没有公布你的结果stunclient
运行,但我想它看起来像下面这样:
$ stunclient --mode full --localport 9999 stunserver.stunprotocol.org
Binding test: success
Local address: 192.168.1.8:9999
Mapped address: 1.2.3.4:9999
Behavior test: success
Nat behavior: Endpoint Independent Mapping
Filtering test: success
Nat filtering: Address and Port Dependent Filtering
我猜测您的行为测试是“端点独立”,过滤测试是“地址和端口相关”,因为这些是家庭中最常见的,并且大多与您上面描述的相匹配。 (又名“端口限制 NAT”)。
无论如何,这意味着您已经在自己和 STUN 服务器之间创建了端口映射。在上面的示例中,我的公共 IP 地址是 1.2.3.4。这是常见的,但并非总是如此,我的本地端口(9999)与公共端口相同。
在内部,您的 NAT 保留一个逻辑表,如下所示:
------------------------------------------------------------------------------------
|| LOCAL IP | LOCAL PORT || EXT PORT || REMOTE IP | REMOTE PORT ||
||================================================================================||
|| 192.168.1.8 | 9999 || 9999 || 107.23.150.92 | 3478 ||
------------------------------------------------------------------------------------
由于您从端口 9999 向 stun 服务器 (107.23.150.92) 发送了一个数据包,因此 NAT 会在其表中创建一个端口映射条目,持续几分钟。当数据包从 Internet 到达 NAT/路由器时,它会查阅该表。当响应从 STUN 服务器的 IP:端口返回时,NAT 能够根据上表中的“远程”字段将其转发到 NAT 后面的计算机。
但是您和您希望从中接收数据的“其他公共计算机”之间没有端口映射。假设另一台计算机的 IP 地址是 2.4.6.8,并且它正在尝试从其本地端口 8888 发送数据。NAT 表中仍然没有任何内容可以将流量从 2.4.6.8:8888 映射到后面的主机NAT。因此,当流量从不在表中的主机到达 NAT 时,NAT 只知道将数据包丢弃在地板上。有一种称为“Cone NAT”的 NAT 分类可以在其中发挥作用,但这些分类并不常见。
对于您的情况,有一个简单的解决方法。从 STUN 服务器获取端口映射后,从同一本地端口 (9999) 向要从中接收数据的远程主机(和远程端口)发送另一个数据报。远程主机可以简单地忽略此数据报,但它会有效地在 NAT 上创建另一个端口映射条目
------------------------------------------------------------------------------------
|| LOCAL IP | LOCAL PORT || EXT PORT || REMOTE IP | REMOTE PORT ||
||================================================================================||
|| 192.168.1.8 | 9999 || 9999 || 107.23.150.92 | 3478 ||
|| 192.168.1.8 | 9999 || 9999 || 2.4.6.8 | 8888 ||
------------------------------------------------------------------------------------
发送到 2.4.6.8:8888 的简单 1 字节数据包允许 NAT 将流量从该地址转发回 NAT 后面的主机。
换句话说,使用您自己的网络流术语:
My machine:9999 ---->[STUN BINDING REQUEST]--->stun server:3478
My machine:9999 <----[STUN BINDING RESPONSE mapped IP:port]<--- stun server:3478
My machine:9999 [Open socket on port 9999]
My machine:9999 ---->[1 byte datagram] -------> 'other:8888'
My machine:9999 <---- [UDP to public IP:port obtained in step 2]<----'other:8888'
通常,在正常的 P2P 流程中,两个端点都与 STUN 服务器一起工作来发现其端口映射。然后使用另一个服务在彼此之间交换IP:端口信息。根据您的描述,您正在程序之间手动交换这些值,这对于测试来说很好。
如果另一台机器位于公共互联网上,从技术上讲,您不需要 STUN。第一台机器(在 NAT 后面)可以直接发送到远程 IP 和端口来表示“向我发送一些数据”。远程端只需检查该消息的对等地址和端口来决定发送回何处。端口映射已经创建。一些 RTSP 客户端假设服务器是公共的
我对套接字 NAT 遍历基础知识的回答是here.
我碰巧认识《STUNTMAN》的开发者。他是一个相当不错的人,英俊,而且非常聪明。他们还说我和他长得很像,而且我们名字的拼写也几乎相同。如果您对 STUN 和 NAT 穿越有疑问,可以直接给他发邮件。