Практичный обход NAT для надежных сетевых подключений

Я видел и читал много похожих вопросов и соответствующие статьи в Википедии (обход NAT, STUN, TURN, Перфорация отверстий TCP), но подавляющее количество информации на самом деле не помогает мне с моей очень простой проблемой:

Я пишу приложение P2P, и я хочу, чтобы два пользователя моего приложения за NAT могли подключаться друг к другу. Соединение должно быть надежным (сопоставимым с надежностью TCP), поэтому я не могу просто переключиться на UDP. Решение должно сегодня работать над общими системами без переконфигурации. Если это поможет, решение может включать подключаемую стороннюю сторону, если не требуется проксировать все данные (например, для получения IP-адресов внешних (WAN)).

Насколько я знаю, единственный вариант - использовать "надежную библиотеку UDP" + пробивка отверстий UDP. Есть ли для этого библиотека (C/С++)? Я нашел enet в вопросе , но он заботится только о первая половина решения.

Что-нибудь еще? Вещи, на которые я смотрел:

  • Teredo tunneling - требует поддержки от операционной системы и/или конфигурации пользователя
  • UPnP переадресация портов - UPnP отсутствует/включен везде
  • Перфорация отверстий TCP кажется экспериментальной и работает только при определенных обстоятельствах.
  • SCTP поддерживается даже меньше, чем IPv6. SCTP через UDP - это просто надежный UDP (см. Выше).
  • RUDP - почти нет основной поддержки
  • Из того, что я мог понять из STUN, STUNT, TURN и ICE, ни один из них не помог мне здесь.

Ответ 1

ICE собирает список потенциальных целевых IP/портов, к которым нужно подключиться. Каждый одноранговый узел собирает их, а затем каждый запускает проверку подключения каждого из кандидатов по порядку до тех пор, пока проверка не пройдет или проверка не завершится.

Когда Алиса пытается подключиться к Бобу, она каким-то образом получает список возможных способов, определенных Бобом - она ​​может связаться с Бобом. ICE называет этих кандидатов. Боб может сказать, например: "Мой локальный сокет 192.168.1.1:1024/udp, моя внешняя привязка NAT (найденная через STUN) - это 196.25.1.1:4454/udp, и вы можете вызвать медиарелейное (промежуточное поле) в 1.2.3.4: 6675/УДП". Боб ставит это в SDP-пакете (описание этих разных кандидатов) и отправляет его Алисе. (В SIP, исходный вариант использования для ICE, SDP, переносимый в обмен SIP INVITE/200/ACK, настройка сеанса SIP.)

ICE подключается, и вы можете настроить точный характер/количество кандидатов. Вы можете попробовать прямую ссылку, а затем спросить STUN сервер для привязки (это пробивает дыру в вашем NAT и сообщает внешнему IP/порт этого отверстия, который вы ввели в описание сеанса), и отбрасывая запрос TURN для передачи ваших данных.

Единственным недостатком для ICE является то, что ваши сверстники обмениваются описаниями SDP, которые вам могут или не нравятся. Другим является то, что поддержка TCP все еще находится в черновик формы, который может или не может быть проблемой для вас. [UPDATE: ICE официально официально RFC 6544.]

Игры часто используют UDP, потому что старые данные бесполезны. (Вот почему RTP обычно работает поверх UDP.) В некоторых приложениях P2P часто используются средние или средние ячейки.

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

В противном случае вы можете взглянуть на архитектуру BitTorrent и посмотреть, как они справляются с проблемой NAT. Как отмечает CodeShadow в комментариях ниже, BitTorrent полагается на доступные одноранговые сети в сети: в некотором смысле некоторые сверстники образуют сеть из средних ящиков. Если эти медиа-боксы могут выступать в качестве реле, у вас будет IRC-подобная архитектура, но динамическая настройка.

Ответ 2

Я рекомендую libjingle, поскольку он используется некоторыми крупными компаниями видеоигр, которые в большой степени полагаются на сетевую связь P2P. (Вы слышали о Steam? Vavle также использует libjingle, см. Сеанс "Одноранговая сеть" на странице: https://partner.steamgames.com/documentation/api)

Однако всегда работающее решение будет использовать сервер ретрансляции. Поскольку для NAT не существует "стандартного" способа, вы должны иметь этот вариант сервера ретрансляции в качестве стратегии возврата, если соединение должно всегда устанавливаться между любыми одноранговыми узлами.