做过 udp 穿 nat 的大神请进

软件和网站开发以及相关技术探讨
回复
saintthor
帖子: 107
注册时间: 2014-05-30 15:45
系统: 14.04
送出感谢: 16 次
接收感谢: 0

做过 udp 穿 nat 的大神请进

#1

帖子 saintthor » 2017-01-16 18:00

首先,我测试了本地的NAT,是端口严格的圆锥型。

我在服务器上运行一个 server,有终端连过来就记住,当终端数达到两个时,将每个终端的地址发给另一个终端。两个(nat后面的)终端收到对方的公网地址,同时相对发消息,我希望两个终端能互通。我在本地机器上运行两个终端,它们互相发的总是收不到。

服务器代码:
--------------------------------------------------------------------------
import socket
from time import sleep

s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
s.bind(( '0.0.0.0', 9876 ))
addrs = set()
while len( addrs ) < 2:
- data, addr = s.recvfrom( 1024 )
- addrs.add( addr )

print 'got 2 addrs.'
addrs = list( addrs )

s.sendto( repr( addrs ), addrs[1] )
s.sendto( repr( addrs ), addrs[0] )

print 'addrs sent.'
while True:
- sleep( 1 )
- print s.recvfrom( 1024 )
- s.sendto( 'from server', addrs[0] )
- s.sendto( 'from server', addrs[1] )

---------------------------------------------------------------------------

终端代码:
---------------------------------------------------------------------------
import socket
s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
s.sendto( 'are you ok?', ( '112.126.173.63', 9876 ))
AddrStr, _ = s.recvfrom( 1024 )
addrs = eval( AddrStr )
print 'got addrs', repr( addrs )
for i in range( 30 ):
- s.sendto( 'let us begin 0.', addrs[0] )
- s.sendto( 'let us begin 1.', addrs[1] )
- s.sendto( 'notice server.', ( '112.126.173.63‘, 9876 ) )
- s.settimeout( 0.3 )
- try:
-- print s.recvfrom( 1024 )
- except socket.timeout:
-- pass
---------------------------------------------------------------------------

运行时,两个终端都能收到双方的公网地址(我怕弄反了,所以两个都传),但后面分别向两个地址发的 s.sendto( 'let us begin 0.', addrs[0] ),对方收不到,自己也收不到。而与此同时,向服务器发的 s.sendto( 'notice server.', ( '112.126.173.63', 9876 ) ) 服务器就收到了。服务器向两个终端发的 s.sendto( 'from server', addrs[0] ) 终端也收得到。

从打印出来的数据看,两个终端的公网地址都是正确的,双方互相发,但彼此收不到。这是为什么?
头像
astolia
论坛版主
帖子: 4842
注册时间: 2008-09-18 13:11
送出感谢: 1 次
接收感谢: 814 次

Re: 做过 udp 穿 nat 的大神请进

#2

帖子 astolia » 2017-01-17 11:05

你是怎么测试NAT的类型的?确定其支持Hairpin了吗?
saintthor
帖子: 107
注册时间: 2014-05-30 15:45
系统: 14.04
送出感谢: 16 次
接收感谢: 0

Re: 做过 udp 穿 nat 的大神请进

#3

帖子 saintthor » 2017-01-17 13:41

astolia 写了:你是怎么测试NAT的类型的?确定其支持Hairpin了吗?
不懂 Hairpin。我从本地向两台服务器发 udp 包,服务器收到的公网地址相同,故认为是圆锥型;向一台服务器的端口A发数据后,从服务器另一端口B回发数据,收不到,故认为是端口受限。
头像
astolia
论坛版主
帖子: 4842
注册时间: 2008-09-18 13:11
送出感谢: 1 次
接收感谢: 814 次

Re: 做过 udp 穿 nat 的大神请进

#4

帖子 astolia » 2017-01-18 20:55

你的代码基本逻辑是没什么问题的。但各人网络环境不一样,你的代码在我这里也不是每次都成功。
在同一个nat内的两个终端要靠公网地址通信,nat必须要支持hairpin特性才行。你所在的nat有可能就不支持。
这些用户感谢了作者 astolia 于这个帖子:
saintthor (2017-01-19 16:42)
评价: 3.7%
saintthor
帖子: 107
注册时间: 2014-05-30 15:45
系统: 14.04
送出感谢: 16 次
接收感谢: 0

Re: 做过 udp 穿 nat 的大神请进

#5

帖子 saintthor » 2017-01-19 16:37

astolia 写了:你的代码基本逻辑是没什么问题的。但各人网络环境不一样,你的代码在我这里也不是每次都成功。
在同一个nat内的两个终端要靠公网地址通信,nat必须要支持hairpin特性才行。你所在的nat有可能就不支持。
这样啊,,谢谢。

如果把两个终端放在不同 nat 后面,支不支持 hairpin 都能互通?

在你那里为什么有时不成功?
头像
astolia
论坛版主
帖子: 4842
注册时间: 2008-09-18 13:11
送出感谢: 1 次
接收感谢: 814 次

Re: 做过 udp 穿 nat 的大神请进

#6

帖子 astolia » 2017-01-19 17:43

穿NAT的常规做法就是客户端也要向服务端报告自己的内网地址,其他客户端从服务器获取后,优先尝试连内网地址。这样即提高了速度又可以无视Hairpin限制。不同NAT之间本来就没有Hairpin的说法

至于为什么会不成功,这个可能的原因太多了。UDP本来就不可靠,又比较容易被QoS盯上,如果是和境外服务器连接,还要考虑墙的存在,就更难说了
这些用户感谢了作者 astolia 于这个帖子:
saintthor (2017-01-20 17:55)
评价: 3.7%
回复

回到 “软件/网站开发”