我读了一些关于UDP NAT遍历的文章,我有理由相信我理解了基本原理,但我仍然在努力实现。在
我的项目有一个全局可访问的服务器,以及nat后面的客户端。这是一个游戏,用基本的join_game请求从客户端发送到服务器,然后服务器每隔一段时间发送更新。我一直在家里测试,却忘了路由器上的DMZ打开了,所以它工作得很好。我把这个发给了一些朋友来测试,他们无法从服务器接收更新。在
以下是当前的方法,所有数据包都是UDP:
我的理解是服务器接收到的应答地址应该有正确的端口来遍历客户机的nat。经常发送数据包将使nat遍历规则保持有效。在
这不会发生。客户端的join请求被发送到服务器上,然后接收该请求。但是当我关闭这个套接字,然后在回复端口上启动一个线程化的UDP侦听器时,它没有捕捉到任何东西。这就好像遍历规则只对单个响应包有效。在
如果需要的话,我可以包含代码,但是说实话,它有几个层类和对象,并且它做了我上面描述的事情。当我打开DMZ时,代码可以工作,但当它关闭时就不行了。在
我将包括一些有趣的片段。在
这里是服务器的join请求处理程序。客户机地址从线程处理程序向下传递,并且是SocketServer.BaseRequestHandler属性,自身客户地址. 没有解析,只是传下来了。在
def handle_player_join(self, message, reply_message, client_address):
# Create player id
player_id = create_id()
# Add player to the connected nodes dict
self.modules.connected_nodes[player_id] = client_address
# Create player ship entity
self.modules.players[player_id] = self.modules.factory.player_ship( position = (320, 220),
bearing = 0,
)
# Set reply to ACK, and include the player id and listen port
reply_message.body = Message.ACK
reply_message.data['PLAYER_ID'] = player_id
reply_message.data['LISTEN_PORT'] = client_address[1]
print "Player Joined :"+str(client_address)+", ID: "+str(player_id)
# Return reply message
return reply_message
一个朋友提到,也许当我发送join请求,然后得到响应时,我不应该关闭套接字。让那个插座保持活动状态,让它成为侦听器。我不相信关闭套接字会对nat遍历产生任何影响,我也不知道如何生成一个线程化的udp侦听器,它接受一个预先存在的套接字而不重写整个该死的东西(我宁愿不重写)。在
需要什么想法或信息吗?在
干杯
你可以做两件事中的任何一件使你的代码工作。是的
不要关闭将数据包发送到服务器的套接字。当您创建一个套接字时,它绑定到一个私有的IP:Port。当您向服务器发送数据包时,该IP:Port将转换为您的nat一个公共IP:Port。现在,当您关闭这个套接字时,来自服务器的数据首先到达您的NATs公共IP:Port并被转发到您的私有IP:Port。但是由于你的套接字是关闭的,所以没有人会收到这些数据。现在服务器无法知道您已经用新的private IP:Port创建了一个新的套接字,因为在创建这个新的套接字之后,您从未向服务器发送过数据包。所以不要关闭旧插座。试着用这个老的来听。或者,您可以从新的套接字向服务器发送一个数据包,让它知道您新翻译的公共IP:Port。这样服务器就可以把它的数据发送到这个新的公共IP:Port,这个端口又将被转发到您的新的私有IP:Port。在
关闭插座,但重复使用同一端口。关闭旧套接字并创建新套接字时,将其绑定到绑定旧套接字的端口。这不会更改NATs公共IP:端口,来自服务器的数据将不会中断。在
相关问题 更多 >
编程相关推荐