Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Не могу пробить NAT, UDP создает канал

Не могу пробить NAT, UDP создает канал

Страницы: 1 2 3 4 5 6 7 Следующая »
RammПостоялецwww3 дек. 201715:54#0
Добрый день!
Проблема частая, но я попытаюсь все описать подробно-подробно. К тому же маюсь я с ней уже несколько месяцев...
Есть сервер с белым IP, и есть клиент за NAT-ом и роутером. Клиент и сервер создают сокеты на UDP, клиент отправляет пакет на сервер, сервер его успешно получает, вычисляет его обратный адрес и порт, отправляет на него ответ. Все прекрасно работает, пакеты летают, обмен идет.
Проблема возникла, когда я решил подключить второго клиента к первому, т.е. чтобы второй клиент мог отправить пакеты первому.
На сокет первого клиента (который за NAT-ом) доходят пакеты ТОЛЬКО с сокета сервера, на который этот первый клиент первоначально сбрасывал пакет.

Пишу все на C#.

Т.е. ситуация полностью выглядит так:
1. На сервере с белым IP создаю 2 сокета UDP, которые слушают разные порты, например 35000 и 36000

    Socket udp35000, udp36000;

    *****

            udp35000 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint ClientEP1 = new IPEndPoint(IPAddress.Any, 35000);
            udp35000.Bind(ClientEP1);

            udp36000 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint ClientEP2 = new IPEndPoint(IPAddress.Any, 36000);
            udp36000.Bind(ClientEP2);
2. На клиенте создаю 1 сокет UDP, отправляю пакет на первый сокет сервера.
    Socket udp_;

    *****

            udp_ = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint localIP = new IPEndPoint(IPAddress.Any, 27015);
            udp_.Bind(localIP);

            string message = "ready_message";
            byte[] _data = Encoding.ASCII.GetBytes(message);
            EndPoint remotePoint = new IPEndPoint(IPAddress.Parse("тут адрес сервера"), 35000);
            udp_.SendTo(_data, remotePoint);
3. Сервер получает пакет, вычисляет его обратный адрес и отправляет ответ:
              byte[] data = new byte[256];
              int bytes = 0;
              //узнаем адрес, с которого пришли данные
              EndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);
                while (udp35000.Available > 0)
                {
                    bytes = udp35000.ReceiveFrom(data, ref remoteIp);
                    // получаем данные о подключении
                    IPEndPoint remoteFullIp = remoteIp as IPEndPoint;
                    //отправляем ответку
                    string message = "it's ok";
                    byte[] _data = Encoding.ASCII.GetBytes(message);
                    EndPoint remotePoint = new IPEndPoint(remoteFullIp.Address, remoteFullIp.Port);
                    udp35000.SendTo(_data, remotePoint);
    }
4. Сообщения с этого сокета ДОХОДЯТ!!!
5. Пытаюсь отправить со второго сокета сервера сообщения на этот адрес - они не приходят.
udp36000.SendTo(_data, remotePoint);
udp36000.SendTo(_data, remotePoint);
udp36000.SendTo(_data, remotePoint);
- пакеты отправляются, но не доходят.

Как преодолеть этот NAT и почему пакеты не доходят, хоть я и шлю их на внешний адрес и порт клиента??? И что вообще делать?

П.С. Вот тут:
http://www.gamedev.ru/code/forum/?id=194840&page=2
у людей аналогичные проблемы, но там сказано

Как это работает: когда вы шлете что-то из-за NATа по UDP, вам выделяется на время внешний порт на роутере, который связывается с внутренним портом на вашем компе. На этот порт вам могут слать все что угодно. Связка портов держится некоторое время после того, как ей последний раз воспользовались. В зависимости от настроек роутера, от 20 минут, до 4х часов.
Однако, можно так настроить роутер, чтобы он запоминал, куда была первая передача, и принимал встречные посылки только из этого адреса. По умолчанию они обычно настроены так, чтобы принимать из любых адресов.

Т.е. доходить должно...
П.С.2
На клиенте я заранее забиндил неслучайный порт для сокета (27015), если этого не сделать - система выделит свободный:
            IPEndPoint localIP = new IPEndPoint(IPAddress.Any, 27015);
            udp_.Bind(localIP);
Так вот, если так делать, то на сервере функция ReceiveFrom(data, ref remoteIp) определяет, что обратный порт, с которого пришел пакет - 27015. И так при каждом запуске!!! Закрадываются мысли, что это не внешний порт, но ведь пакеты с сокета udp35000 как-то доходят до клиента, даже с этим портом!!!
П.С.3 На другом форуме сказали, что NAT запоминает куда я отправил и получает ответ только оттуда... И как тогда половина сетевых программ функционирует? Или все 100% пересылают через выделенные сервера?

Рад любому пояснению или примерам, лучше на C#, но сгодится любой язык...

GorunuchПостоялецwww3 дек. 201718:46#1
Цитата из книги:
Сначала узел А пошлет пакет с порта 200 посреднической службе с IP-адресом
4.6.5.10 (узел П), сообщая, что хотел бы зарегистрироваться в роли сервера. Когда
пакет попадет на маршрутизатор NAT А, он создаст запись в своей таблице NAT
и изменит пакет, заменив адрес отправителя своим глобальным IP-адресом, а порт
отправителя — случайным числом, в нашем примере 60000 . Затем маршрутизатор
NAT А отправит пакет узлу П. Узел П примет пакет и узнает, что игрок А, играю-
щий на узле А с адресом 18.19.20.21:60000 , желает зарегистрироваться как сервер
многопользовательской игры.
Затем узел Б пошлет узлу П пакет, сообщающий, что игрок Б хотел бы подклю-
читься к игре игрока А. Когда пакет попадет на маршрутизатор NAT Б, тот создаст
запись в своей таблице NAT и изменит пакет, подобно тому как это сделал марш-
рутизатор А. Затем измененный пакет будет отправлен узлу П, который узнает
из пакета, что узел Б с адресом 12.12.6.5:62000 хотел бы соединиться с узлом А.
В этот момент узел П уже знает глобальный адрес маршрутизатора NAT А, а также
порт получателя, через который маршрутизатор NAT А перешлет пакет узлу A.
Узел П мог бы послать эту информацию узлу Б в пакете ответа и потребовать,
чтобы узел Б попытался использовать ее для соединения. Но не забывайте, что
некоторые маршрутизаторы проверяют происхождение входящих пакетов, чтобы
гарантировать, что эти пакеты ожидаются с указанного адреса. Маршрутизатор
NAT А пока ожидает получить только пакеты от узла П. Если узел Б сейчас по-
пытается подключиться к узлу А, маршрутизатор NAT А заблокирует пакет, потому
что он не ожидает получить ответ от узла Б.
К счастью, узел П также знает глобальный IP-адрес маршрутизатора NAT Б и но-
мер порта, через который можно отправить пакет узлу Б. Поэтому он посылает
данную информацию узлу А. Маршрутизатор NAT А пропускает эту информацию,
потому что в его таблице NAT есть запись, сообщающая, что узел А ждет ответа от
узла П. Затем узел А посылает пакет узлу Б, используя информацию, полученную
от узла П. Может показаться странным, что сервер пытается соединиться с клиен-
том, тогда как обычно все делается наоборот. Еще более странной данная ситуация
будет выглядеть, если вспомнить, что маршрутизатор NAT Б не ожидает получить
пакет от узла А и потому просто не пропустит его. Зачем тогда напрасно посылать
пакет? Таким способом узел А вынуждает маршрутизатор NAT А создать запись
в своей таблице NAT!
Пакет, отправленный узлом А узлу Б, попадет в маршрутизатор NAT А. Маршрути-
затор обнаружит, что адрес узла А 192.168.1.2:200 уже есть в таблице с внешним
портом 60000 , поэтому он выберет этот порт для исходящего пакета. Затем создаст
еще одну запись в таблице, указывающую, что с адреса 192.168.1.2:200 отправлен
пакет на адрес 12.12.6.5:62000 . Эта дополнительная запись является ключевой.
Пакет почти наверняка никогда не достигнет узла Б, но после его отправки узел П
сможет послать ответ узлу Б, сообщая, что тот может подключиться непосред-
ственно к узлу А по адресу 18.19.20.21:60000 . Узел Б так и поступит, и когда пакет
достигнет маршрутизатора NAT А, тот увидит, что это действительно ожидаемый
входящий пакет с адреса 12.12.6.5:62000 . Он изменит пакет, подставив адрес полу-
чателя 192.168.1.2:200 , и отправит его узлу А. С этого момента узлы А и Б смогут
взаимодействовать непосредственно друг с другом, используя глобальные IP-
адреса и номера портов, которыми они обменялись.
ZabПостоялецwww3 дек. 201719:32#2
Пробивать со стороны клиента ты должен каждый порт, на который хочешь что-то получать. Каждому из них NAT назначит свой натовский порт, они ни разу не совпадают с номерами портов, которые у тебя прописаны в клиенте. Оба не совпадают. Сервер должен их оба запомнить, а потом на эти порты может кто угодно слать сообщения, не только сервер.
Биндить на клиенте тоже желательно оба порта, хотя udp этого жестко и не требует.
PANDAПостоялецwww3 дек. 201720:18#3
Самый простой вариант - заиспользовать UPnP на стороне клиента за NAT'ом. Поищи либу для этого. Когда клиент пробросит порт, нужно будет этот порт переслать через сервер другому клиенту и тот сможет открыть соединение.
RammПостоялецwww3 дек. 201720:21#4
Zab
Нет-нет, на клиенте только 1 сокет и порт, мне не нужно больше. Я успешно соединяюсь с одним сокетом сервера, и тот нормально принимает-отправляет пакеты от клиента. Другие, даже другой сокет сервера не может пробиться к клиенту.

Или тут о каких-то других портах речь?

Я правильно понял, что я внешний порт неверно получаю? Он неможет совпадать с портом, который я забиндил? И как мне получить настоящий внешний порт?
И почему с первого сокета сервера все нормально доходит, хоть я и указываю порт 27015?

Gorunuch

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

И вот как узнать, я же получаю неизмененный пакет, похоже, хоть и IP внешний.
В общем, я на функцию RecieveFrom грешу...

Правка: 3 дек. 2017 20:30

RammПостоялецwww3 дек. 201721:05#5
PANDA
Сейчас, похоже, у меня одна проблема -    узнать внешний порт, с этим и стандартные средства должны справиться. Да и внешний сервер есть... А что за либы и зачем, если UPnP стандартные сокеты С# держат, вроде...
PANDAПостоялецwww3 дек. 201722:26#6
Ramm
> Сейчас, похоже, у меня одна проблема - узнать внешний порт
Это во многих случаях тебе никак не поможет. Короче, читай UPnP и поймешь, что и зачем. Если у тебя нет полного понимания, как работает NAT и какие бывают нюансы на разных роутерах, то пытаться самому пробивать его - глупая затея.
RammПостоялецwww4 дек. 20178:47#7
PANDA
> Если у тебя нет полного понимания, как работает NAT и какие бывают нюансы на
> разных роутерах, то пытаться самому пробивать его - глупая затея.
Да вроде не все так сложно... Роутер тоже должен уметь делать свой NAT. Например, к роутеру подключены 5 устройств и все дружно лезут в браузер по 80-му порту, роутер не может обслуживать их всех, поэтому выделяет для каждого пользователя свой порт (из числа свободных) и посылает трафик дальше. Запоминая какой порт и для кого он выделил. На выходе NAT провайдера, и там та же самая ситуация, выделяет свободные порты, запоминает что и для кого выделил, и посылает пакеты дальше. Сервер получает пакеты от самого последненго адреса и порта и шлет ответы на них. NAT ответные пакеты он пересылает обратно на нужные порты, а те переходят по иерархии еще ниже.

Если роутер не умеет так делать, то это вообще не моя проблема и UPnP не поможет. Куча тем в инете, где люди не могут поиграть в нормальные игры вместе с "модель роутера что делать". У меня почти все получается, только какая-то фигня с определением внешнего порта. Все должно работать и со стандартными сокетами.
PANDA
> Короче, читай UPnP и поймешь, что и зачем.
Кроме сторонних библиотек по запросу "C# upnp" и вопросов о том, как их использовать, а так же граблей и костылей, я ничего толкового не нашел.

DampireПостоялецwww4 дек. 20179:57#8
Ramm
> все дружно лезут в браузер по 80-му порту, роутер не может обслуживать их всех
Это сервер сидит на 80 порту. А клиенты подключаются с любого, который пожелает браузер. Почитай про UDP hole punching и TCP hole punching. Особенно в каких условиях оно может работать, а в каких нет. Может дойдет наконец. В том треде, в котором ты отписался ответ на вопрос был. Но зачем читать, если можно не читать? Намекну. Симметричный нат, фулл кон, рестриктед кон, порт-рестриктед кон.

Еще статья про UPnP. Она к твоему вопросу вообще никаким боком не относится. Как и вообще UPnP. Но для общего развития сойдет.
https://habrahabr.ru/post/279969/

Правка: 4 дек. 2017 10:04

RammПостоялецwww4 дек. 201710:32#9
Dampire
> Это сервер сидит на 80 порту. А клиенты подключаются с любого, который пожелает
> браузер.
Я для примера, но перед этим загуглил, какой обычно порт использует та же Мозила.
Dampire
> Но зачем читать, если можно не читать?
Обижаете, начальник))) Все прочитал. И для "пробивания" NAT я использую свой сервер с белым адресом, по рекомендации Zab

Dampire

Zab
STUN пробивает нат для клиента. Ему покласть на остальных. Он не регистрирует заявки, он ничего не фиксирует. Он всего-лишь пробивает порт и сообщает реальный адрес тому-же серверу, с которого пришел запрос на пробитие, после чего благополучно все забывает. Я че-то протупил этот момент.
St1G
Забей на всю эту ерунду и сделай свой мастер сервер, который будет запоминать пробитые порты для адреса, а затем либо реинвайты кидать, либо гонять траффик через себя. Либо унификация портов, которые кстати могут быть заняты какой-нибудь другой дрянью. Все остальные варианты будут работать без гарантий.

Zab
Похоже я себе не очень хорошо представлял что такое stun-сервер... Он действительно не коллекционирует адреса, и не сообщает их никому, помимо инициировавшего соединение. Но тогда нафиг он нужен? А он и не нужен, и не используется почти нигде...

Требуется средство сообщить одному клиенту адрес и порт другого. И это средство - не stun-сервер. Пробить NAT конечно надо, но это можно сделать отослав сообщение на любой внешний IP, не нужно специальное средство для таких целей. Через что сообщаем свой адрес - через то и пробьем.

Если stun сообщает что у вас статус FullCone, это значит что все отлично, он проверил что ваш NAT так настроен, что может принимать посылки из многих адресов.


Или без стороннего STUN никак не обойтись?
Может дойдет наконец.

Блиииин. А что я не так-то делаю???
DampireПостоялецwww4 дек. 201710:40#10
Я не просто так выделил разные типы натов. И в цитате от Zab есть пометка про Full Cone. И я не просто так отметил про Resticted и Port-Restricted Cone. Может стоит все же почитать что это такое? Как только узнаешь что это, то я тебе подскажу как с этим бороться, если сам не дойдешь в процессе.
RammПостоялецwww4 дек. 201711:17#11
Dampire
Спасибо огромное, что ткнули носом, но сейчас я буду отнимать чье-то время...
Вики говорит:
Симметричный NAT (Symmetric NAT) — Трансляция, при которой каждое соединение, инициируемое парой «внутренний адрес: внутренний порт» преобразуется в свободную уникальную случайно выбранную пару «публичный адрес: публичный порт». При этом инициация соединения из публичной сети невозможна.

Cone NAT, Full Cone NAT — Однозначная (взаимная) трансляция между парами «внутренний адрес: внутренний порт» и «публичный адрес: публичный порт». Любой внешний хост может инициировать соединение с внутренним хостом (если это разрешено в правилах межсетевого экрана).

Address-Restricted cone NAT, Restricted cone NAT — Постоянная трансляция между парой «внутренний адрес: внутренний порт» и «публичный адрес: публичный порт». Любое соединение, инициированное с внутреннего адреса, позволяет в дальнейшем получать ему пакеты с любого порта того публичного хоста, к которому он отправлял пакет(ы) ранее.

Port-Restricted cone NAT — Трансляция между парой «внутренний адрес: внутренний порт» и «публичный адрес: публичный порт», при которой входящие пакеты проходят на внутренний хост только с одного порта публичного хоста — того, на который внутренний хост уже посылал пакет.


И вот еще:
Symmetric NAT. До недавнего времени это была наиболее распространённая реализация. Его характерная особенность – в таблице NAT маппинг адреса IL на адрес IG жёстко привязан к адресу OG, то есть к адресу назначения, который был указан в исходящем пакете, инициировавшем этот маппинг. При указанной реализации NAT в нашем примере хост 192.168.0.141 получит оттранслированные входящие UDP-пакеты только от хоста 1.2.3.4 и строго с портом источника 53 и портом назначения 1053 – ни от кого более. Пакеты от других хостов, даже если указанные в пакете адрес назначения и порт назначения присутствуют в таблице NAT, будут уничтожаться маршрутизатором. Это наиболее параноидальная реализация NAT, обеспечивающая более высокую безопасность для хостов локальной сети, но в некоторых случаях сильно усложняющая жизнь системных администраторов. Да и пользователей тоже.

Full Cone NAT. Эта реализация NAT – полная противоположность предыдущей. При Full Cone NAT входящие пакеты от любого внешнего хоста будут оттранслированы и переправлены соответствующему хосту в локальной сети, если в таблице NAT присутствует соответствующая запись. Более того, номер порта источника в этом случае тоже не имеет значения – он может быть и 53, и 54, и вообще каким угодно. Например, если некое приложение, запущенное на компьютере в локальной сети, инициировало получение пакетов UDP от внешнего хоста 1.2.3.4 на локальный порт 4444, то пакеты UDP для этого приложения смогут слать также и 1.2.3.5, и 1.2.3.6, и вообще все до тех пор, пока запись в таблице NAT не будет по какой-либо причине удалена. Ещё раз: в этой реализации NAT во входящих пакетах проверяется только транспортный протокол, адрес назначения и порт назначения, адрес и порт источника значения не имеют.

Address Restricted Cone NAT (он же Restricted NAT). Эта реализация занимает промежуточное положение между Symmetric и Full Cone реализациями NAT – маршрутизатор будет транслировать входящие пакеты только с определенного адреса источника (в нашем случае 1.2.3.4), но номер порта источника при этом может быть любым.

Port Restricted Cone NAT (или Port Restricted NAT). То же, что и Address Restricted Cone NAT, но в этом случае маршрутизатор обращает внимание на соответствие номера порта источника и не обращает внимания на адрес источника. В нашем примере маршрутизатор будет транслировать входящие пакеты с любым адресом источника, но порт источника при этом обязан быть 53, в противном случае пакет будет уничтожен маршрутизатором.


Предположим, мой внутренний адрес 192.168.0.1, внешний адрес 46.46.128.128...
Если у меня Symmetric NAT, я создаю сокет с портом 27015, отправляю его на IP X с портом 35000, NAT не изменит порт, сервер получит пакет, определит его как от 46.46.128.128:27015, и ТОЛЬКО ОН МОЖЕТ ОТПРАВИТЬ ОТВЕТ. БЕССМЫСЛЕННО ПЕРЕДАВАТЬ 46.46.128.128:27015, Т.К. ДОСТУЧАТЬСЯ ДО НЕГО СМОЖЕТ ТОЛЬКО Х:35000, ОСТАЛЬНЫЕ БУДУТ ОТБРАСЫВАТЬСЯ. Даже если я создам второй сокет на сервере, с портом 36000 - пакет уничтожится.

Если бы у меня был Full Cone NAT, то после отправки первого пакета на сервер Х:35000, я мог бы передавать этот адрес 46.46.128.128:27015 кому хочу, а они могли бы отправлять с любого адреса и порта сообщения, которые доходили бы.

При Address Restricted Cone NAT, мой второй сокет на сервере, с портом 36000 смог бы законнектится к клиенту, а вот другие клиенты, с других IP - нет. Опять же, бесполезно передавать им адрес клиента (46.46.128.128:27015), т.к. отправлять может лишь адрес Х.

При Port Restricted Cone NAT важен лишь порт источника, т.е. я бы мог заранее сказать, что моя прога использует порт 27015, и клиент, и сервер отправляют пакеты только по этому порту - и все работало бы, но второй сокет на сервере с портом 36000 не достучался бы до клиента с портом 27015, как и первый сокет, с портом 35000... Пришлось бы исправить его на 27015.

Итак, что мы имеем, порт клиента, внутренний, который я забиндил - 27015, при этом внешний сервер его и получает, т.е. NAT его не меняет. До клиента за натом может достучаться только тот, до кого достучался клиент, пакеты от других адресов или портов не доходят.
У меня симметричный НАТ.
Я не представляю, как организовать прямую связь. Единственная возможность, которую я вижу, пересылать все пакеты клиентов через сервер.
Dampire
> Как только узнаешь что это, то я тебе подскажу как с этим бороться
Я ГОТОВ! Как бороться с таким натом?

Правка: 4 дек. 2017 11:18

PANDAПостоялецwww4 дек. 201711:29#12
Ramm
> Да вроде не все так сложно... Роутер тоже должен уметь делать свой NAT.
> Например, к роутеру подключены 5 устройств и все дружно лезут в браузер по
> 80-му порту, роутер не может обслуживать их всех, поэтому выделяет для каждого
> пользователя свой порт (из числа свободных) и посылает трафик дальше. Запоминая
> какой порт и для кого он выделил. На выходе NAT провайдера, и там та же самая
> ситуация, выделяет свободные порты, запоминает что и для кого выделил, и
> посылает пакеты дальше. Сервер получает пакеты от самого последненго адреса и
> порта и шлет ответы на них. NAT ответные пакеты он пересылает обратно на нужные
> порты, а те переходят по иерархии еще ниже.
Не так. Клиент не просится на 80 порт роутера. Он просит переслать пакет с назначением по порту 80 (на какой-то сайт в интернете), а роутер в процессе NAT-а подменяет адрес и порт отправителя так, как-будто это сам роутер отправил запрос на тот сайт.
Потом сайт отправляет ответ на исходящий порт роутера, а роутер у себя хранит табличку мапинга и преобразует обратно и отправляет ответ клиенту.
Если клиент пытается послать запрос напрямую другому такому же клиенту за NAT-ом, то роутер другого клиента станет преградой, т.к. никакого маппинга нет. Есть разные способы это обойти путем посылания пакетов друг другу в надежде, что маппинг сохранится и удасться создать линк, но это все работает не на 100%. Чтобы работало на 100% есть готовые технологии, типа UPnP. Клиент просто говорит своему роутеру, что ему надо пробросить порт наружу и весь трафик, который идет на этот порт роутера автоматически пересылать клиенту. После того, как твоя программа пробросила порт все работает элементарно. Единственное ограничение: роутер должен уметь UPnP (сейчас все практически умеют) и он должен быть включен (проблема самого клиента, с которой он может справиться).
DampireПостоялецwww4 дек. 201711:55#13
Ramm
> При Port Restricted Cone NAT важен лишь порт источника, т.е. я бы мог заранее
> сказать, что моя прога использует порт 27015, и клиент, и сервер отправляют
> пакеты только по этому порту - и все работало бы, но второй сокет на сервере с
> портом 36000 не достучался бы до клиента с портом 27015, как и первый сокет, с
> портом 35000... Пришлось бы исправить его на 27015.
Полная фигня или ты плохо объясняешь. Ты стукнулся на сервер 123.123.123.123:1234 с 10.10.10.10:5555 (внешний адрес уже рассматриваем). И теперь сервер может отвечать тебе на 10.10.10.10:5555 только со своего порта под номером 1234. Если он будет слать тебе данные с 123.123.123.123:1235, то пакеты будут просто игнорироваться. То есть. Если в Restricted Cone - ограничение по IP, к которому ты стучался, то в Port-Restricted Cone - ограничение по IP и по порту. Капиш? Теперь понятно почему у тебя ничего не работает? У тебя либо Port-Restricted Cone, либо Симметричный. Это к вопросу о твоей проблеме.

А теперь приходим к решению. Если у тебя оба клиента будут на симметричном или пара симметричный/port-restricted - хрен ты их соединишь через панчинг. Это просто невозможно (или я не знаю как). Тут только различные UPnP технологии применимы или прокси/туннели.
Если у тебя есть хоть один клиент, который ты нормально запанчил (то есть открылся порт наружу для всех в режиме Full Cone), то решение по-моему очевидно. Мастер-сервер должен сообщить всем проблемным клиентам "а вот стукнитесь на этот адрес и порт, вас там ждут". Также есть несколько менее очевидных техник, как одновременная отправка пакетов (с предварительным согласованием с мастер-сервером). То есть допустим у тебя 2 port restricted клиента. Чтобы пробить нат, то ты кидаешь "одновременно" по переданным мастер-сервером портам. Разумеется скорее всего эти пакеты не дойдут, но дырки уже пробиты и следующие пакеты проходить будут.
Детальнее:

client1->master [listening on addr1:port1]
client2->master [listening on addr2:port2]
client2->master [need link to client1]
master->client2 [client1 is on addr1:port1]
master->client1 [requested by client2 on addr2:port2]
client1->client2 [sending packet to addr2:port2] // вот тут пробивается пара
client2->client1 [sending packet to addr1:port1] // на клиенте1 и на клиенте2. эти пакеты не дойдут, но это и не нужно.
// дальше идет общение напрямую

В твоем случае - мастер должен попросить клиента стукнуться на udp36000, после чего канал будет пробит и все будет работать. Заодно по номеру порта определишь - симметричный у тебя нат или просто порт-рестриктед (что более вероятно).

Правка: 4 дек. 2017 11:58

DampireПостоялецwww4 дек. 201712:06#14
PANDA
> проблема самого клиента, с которой он может справиться
Прокинуть порты он тоже может, так что NAT это в целом проблема пользователя. UDP панчинг работает достаточно неплохо, если уметь определять типы натов. Не 100% конечно, но шансы высокие даже на ISP (который 146% не будут работать с UPnP).
Страницы: 1 2 3 4 5 6 7 Следующая »

/ Форум / Программирование игр / Сеть

2001—2018 © GameDev.ru — Разработка игр