2015-09-21 2 views
1

Я проделал некоторое чтение об обходах UDP NAT, и я уверенно понимаю, что я понимаю основы, но я все еще боюсь реализации.python server-client nat traversal

В моем проекте имеется глобально доступный сервер и клиенты позади nat. Его игра с базовым запросом join_game отправляет с клиента на сервер, а затем сервер отправляет обновления каждый интервал. Я тестировал дома и забыл, что у меня есть DMZ на моем маршрутизаторе, и он работал нормально. Я отправил это друзьям для тестирования, и они не могут получать обновления с сервера.

Вот текущая методология, все пакеты UDP:

  • Клиент открывает сокет и посылает запрос на подключение к серверу.
  • Сервер получает запрос и ответный адрес сообщения и отвечает клиенту: да, вы можете присоединиться, и, кстати, я буду отправлять обновления вашего ответа на ip/port, который выглядит следующим образом: ,
  • Клиент улавливает ответ, затем закрывает сокет и запускает прослушивающий класс прослушивателя UDP, чтобы прослушать ответ-порт, о котором нам рассказал сервер.
  • Затем клиент захватывает обновляемые обновления сервера и обрабатывает их по мере необходимости. Время от времени клиент открывает новый сокет и отправляет пакет UDP с обновлением на сервер (какие клавиши нажаты и т. Д.).

Мое понимание - это ответный адрес, который получает сервер, должен иметь правильный порт для перемещения 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 

Друг упомянул, что, возможно, когда я отправлю запрос на соединение, то получите ответ, который я не должен закрывать сокет. Держите этот разъем живым и сделайте это слушателем. Я не уверен, что закрытие сокета будет иметь какое-то влияние на обходные пути, и я не знаю, как создать нерелевантный прослушиватель udp, который берет уже существующий сокет, не переписывая всю проклятую вещь (что я бы предпочел не).

Какие-либо идеи или информация требуется?

Приветствия

+0

Обычно NAT выполняется маршрутизатором/брандмауэром. Клиент не имеет ничего общего с NAT, на самом деле клиент просто знает, куда отправлять все эти пакеты. Я не знаю, какая у вас настройка сети? Может быть, маршрутизатор/брандмауэр на сторонах вашего друга неправильно настроен для выполнения NAT? Какой тип NAT это? Как вы проверили дома? Был ли сервер и клиент в локальной сети с маршрутизатором между ними? «Я не уверен, что закрытие сокета будет иметь какое-то влияние на прохождение nat». В случае «PAT» это срабатывает! –

+0

У моих друзей стандартный маршрутизатор/модем, который вы получаете бесплатно с любым интернет-пакетом. Обычный интернет в модем, базовая ЛВС в доме. То же, что и моя настройка, за исключением того, что я включил DMZ для своей машины. Выключение DMZ заставило его перестать работать. Питон был упакован в исполняемый файл pyinstaller, и когда вы запустите его, Win7 просит разрешения подключить его к сети (которую они приняли). Я запускал его исключительно из сценариев, а также на моей машине без DMZ, и это не работает. В наших сетевых настройках нет ничего необычного :( – Oliver

+0

Что вы имеете в виду, в случае использования PAT? – Oliver

ответ

0

Вы можете сделать любое одно из двух вещей, чтобы сделать ваш код работать.Они:

Не закрывайте розетку, из которой вы отправили пакеты на сервер. Когда вы создаете сокет, он связывается с частным IP: Port. Когда вы отправляете пакет на сервер, этот IP: порт будет переведен на ваши NAT один открытый IP: порт. Теперь, когда вы закрываете этот сокет, данные с вашего сервера сначала поступают на ваш IP-адрес NAT: Порт и перенаправляется на ваш частный IP-порт. Но поскольку ваш сокет закрыт, никто не получит эти данные. Теперь сервер не знает, что вы создали новый сокет с новым частным IP-портом, потому что вы никогда не отправляли пакет на свой сервер после создания нового сокета. Поэтому не закрывайте старый сокет. Попробуйте послушать этот старый в потоке. Или вы можете отправить пакет на сервер из нового сокета, сообщив ему свой новый переведенный публичный IP: Порт. Таким образом, сервер может отправлять свои данные на этот новый общедоступный IP-порт: порт, который, в свою очередь, будет перенаправлен на ваш новый частный IP-порт.

Закройте розетку, но повторно используйте тот же порт. Когда вы закроете свой старый сокет и создаете новый сокет, привяжите его к порту, на котором был связан старый сокет. Это не изменит открытый IP-адрес NAT: порт и данные с вашего сервера не будут прерваны.