我已经完成了关于UDP NAT遍历的一些阅读,并且我有理由相信我理解了基础知识,但我仍然在努力实现。
我的项目有一个全局可访问的服务器,以及nat后面的客户端。它是一个游戏,基本的join_game请求从客户端发送到服务器,然后服务器每隔一段时间发送一次更新。我一直在家里测试,忘了我的路由器上有DMZ,所以它工作正常。我发送给一些朋友进行测试,他们无法从服务器接收更新。
这是当前的方法,所有数据包都是UDP:
我的理解是服务器收到的回复地址应该有正确的端口来遍历客户端的nat。并且经常在那里发送数据包将使nat遍历规则保持活跃。
这没有发生。客户端发送加入请求,并在该套接字上接收服务器的响应。但是当我关闭套接字然后在回复端口上启动一个线程UDP监听器时,它并没有捕获任何东西。它几乎就像遍历规则仅对单个响应数据包有效。
如果需要,我可以包含代码,但说实话它的几个层类和对象,它完成我上面描述的。当我打开DMZ时代码有效,但是当它关闭时则无效。
我将包含一些感兴趣的片段。
这是加入请求的服务器处理程序。 client_address从线程处理程序传递下来,并且是SocketServer.BaseRequestHandler属性self.client_address。没有解析,只是传下来。
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
一位朋友提到,当我发送加入请求时,可能会收到我不应该关闭套接字的响应。保持该套接字存活,并使其成为监听器。我不相信关闭套接字会对nat遍历产生任何影响,而且我不知道如何生成一个带有预先存在的套接字的线程udp监听器而不重写整个该死的东西(我和#39; d而不是)。
需要任何想法或信息吗?
干杯
答案 0 :(得分:1)
您可以执行以下任何一项操作来使代码正常工作。他们是,
不要关闭已将数据包发送到服务器的套接字。创建套接字时,它会绑定到私有IP:端口。当您向服务器发送数据包时,IP:端口将转换为您的NAT一个公共IP:端口。现在,当您关闭此套接字时,服务器中的数据首先出现在您的NAT公共IP:端口,并转发到您的私有IP:端口。但是当你的套接字关闭时,没有人会收到这些数据。现在,服务器无法知道您是否使用新的专用IP创建了新的套接字:端口,因为在创建此新套接字后,您从未向服务器发送过数据包。所以不要关闭旧套接字。尝试在线程中听这个旧的。或者您可以从新套接字向服务器发送数据包,让它知道您的新翻译公共IP:端口。这样服务器就可以将其数据发送到这个新的公共IP:端口,然后将其转发到新的私有IP:端口。
关闭套接字但重用相同的端口。关闭旧套接字并创建新套接字时,将其绑定到旧套接字绑定的端口。这不会更改NAT公共IP:服务器端口和数据不会中断。