Python服务器-客户端NAT遍历



我已经做了一些关于UDP NAT穿越的阅读,我有理由相信我了解基本知识,但我仍然在努力实现。

我的项目有一个全局可访问的服务器,和nat后面的客户端。这是一个游戏,基本的join_game请求从客户端发送到服务器,然后服务器发送更新每隔一段时间。我一直在家里测试,忘记了我在路由器上打开了DMZ,所以它工作得很好。我把这个发给一些朋友测试,他们无法从服务器收到更新。

这是当前的方法,所有数据包都是UDP:

  • 客户端打开一个套接字,向服务端发送连接请求。
  • 服务器获得请求和消息的回复地址,并回复客户端:是的,你可以加入,顺便说一下,我将发送更新到你的回复ip/端口,看起来像这样。
  • 客户端捕获应答然后关闭套接字,并启动一个UDP线程侦听器类来侦听服务器告诉我们的应答端口。
  • 客户端然后捕获被淹没的服务器更新,并根据需要处理它们。每隔一段时间,客户端打开一个新的套接字,并发送一个带有更新的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侦听器,它需要一个预先存在的套接字而不重写整个该死的东西(我宁愿不)。

需要什么想法或信息吗?

欢呼

您可以做以下两件事中的任何一件来使您的代码工作。,

不要关闭您向服务器发送数据包的套接字。当您创建套接字时,它绑定到一个私有IP:Port。当您向服务器发送数据包时,该IP:Port将被转换为您的nat的一个公共IP:Port。现在,当您关闭此套接字时,来自服务器的数据首先到达您的nat公共IP:Port,然后转发到您的私有IP:Port。但是由于您的套接字是关闭的,所以没有人会接收到该数据。现在,服务器无法知道您已经创建了一个具有新的私有IP:Port的新套接字,因为在创建这个新套接字之后,您从未向服务器发送过数据包。所以不要关闭旧插座。试着听听这个旧的。或者您可以从新的套接字向服务器发送一个数据包,让它知道您的新转换的公共IP:Port。这样服务器就可以把它的数据发送到这个新的公共IP:Port,而这些数据又会被转发到你的新的私有IP:Port。

关闭套接字,但重用相同的端口。当您关闭旧套接字并创建新套接字时,将其绑定到绑定旧套接字的端口。这不会改变nat的公共IP:端口和来自服务器的数据将不会中断。

最新更新