TCP Hole Punching - PullRequest
       47

TCP Hole Punching

17 голосов
/ 11 января 2012

Я пытаюсь реализовать перфорацию TCP с помощью сокета Windows, используя mingw toolchain.Я думаю, что процесс правильный, но дыра , похоже, не занимает.Я использовал этот в качестве справочного.

  1. A и B подключение к серверу S
  2. S отправляет A , B IP-адрес маршрутизатора + порт, который использовался для подключения к S
  3. S делает то же самое для B
  4. A запуск 2 потоков:
    • Один поток пытается подключиться к * 1036Маршрутизатор * B с информацией, отправленной S
    • Другой поток ожидает входящего соединения на том же порту, который использовался для подключения к маршрутизатору при подключении к S
  5. B делает то же самое

У меня нет проблем в коде, который я думаю, так как:

  • A и B получает IP-адрес и порт друг друга для использования
  • Они оба прослушивают порт, который они использовали для подключения к своемумаршрутизатор, когда они связались с сервером
  • Они оба подключаются к нужному ip и порту, но получают времяt (ошибка кода 10060)

Я что-то упустил?

РЕДАКТИРОВАТЬ: С помощью Process Explorer, я вижу, что один из клиентаудалось установить соединение с пэром.Но узел, похоже, не считает, что соединение установлено.

Вот то, что я запечатлел с помощью Wireshark.Для примера, сервер S и клиент A находятся на одном компьютере.Сервер S прослушивает определенный порт (8060), перенаправленный на этот ПК. B по-прежнему пытается подключиться к нужному IP-адресу, поскольку видит, что открытый адрес A , отправленный S , равен localhost и поэтому использует открытый IP-адрес S вместо.(Я заменил общедоступные IP-адреса местозаполнителями)

wireshark

EDIT 2 : Я думаю, что путаница связана с тем, что и входящий и исходящий запрос на подключениеданные передаются по одному и тому же порту.Который, кажется, портит состояние соединения, потому что мы не знаем, какой сокет получит данные из порта.Если я приведу msdn:

Опция сокета SO_REUSEADDR позволяет сокету принудительно связываться с портом, используемым другим сокетом.Второй сокет вызывает setsockopt с параметром optname, установленным в SO_REUSEADDR, и параметром optval, установленным в логическое значение TRUE, перед вызовом bind на том же порту, что и исходный сокет. Как только второй сокет успешно связан, поведение для всех сокетов, связанных с этим портом, является неопределенным.

Но для разговора по одному и тому же порту требуется техника перфорации отверстий TCP для открыть отверстия !

Ответы [ 4 ]

12 голосов
/ 19 января 2012

Начало 2 потока:
Один поток пытается подключиться к маршрутизатору B с информацией, отправленной S
Другой поток ожидает входящего подключения через тот же порт, который использовался для подключения к его маршрутизатору, когдаон подключен к S

Вы не можете сделать это с двумя потоками, так как это всего лишь одна операция.Каждое TCP-соединение, которое устанавливает исходящее соединение, также ожидает входящего соединения.Вы просто вызываете 'connect', и вы одновременно отправляете исходящие SYN для установления соединения и ожидаете входящих SYN для установления соединения.

Однако вам может потребоваться закрыть соединение с сервером.Скорее всего, ваша платформа не позволяет вам устанавливать TCP-соединение с портом, если у вас уже есть установленное соединение с того же порта.Поэтому, как только вы начнете пробивать дыры в TCP, закройте соединение с сервером.Свяжите новый сокет TCP с этим же портом и вызовите connect.

1 голос
/ 19 января 2012

Простое решение для прохождения через NAT-маршрутизаторы состоит в том, чтобы заставить ваш трафик следовать протоколу, который у вашего NAT уже есть алгоритм переадресации, такой как FTP.

0 голосов
/ 17 января 2012

не каждый маршрутизатор поддерживает пробивание отверстий по протоколу tcp, пожалуйста, ознакомьтесь со следующей статьей, в которой подробно объясняется:

Одноранговая связь через трансляторы сетевых адресов

0 голосов
/ 11 января 2012
  1. Используйте Wireshark для проверки правильности запроса на соединение TCP (3-сторонний процесс Handhsake).

  2. Убедитесь, что ваш поток прослушивателя имеет функцию select () для демультиплексирования дескриптора.

  3. sockPeerConect (сокет, используемый для подключения другого партнера) - это FD_SET () в потоке слушателя.

  4. Убедитесь, что вы проверяете

     int Listener Thread()
     {
       while(true)
       {
           FD_SET(sockPeerConn);
           FD_SET(sockServerConn);
           FD_SET(nConnectedSock );
          if (FD_ISSET(sockPeerConect)
          {
            /// and calling accept() in side the
            nConnectedSock = accept( ....);
    
           }
           if (FD_ISSET(sockServerConn)
           {
            /// receive data from Server
            recv(sockServerConn );
    
           }
           if (FD_ISSET(nConnectedSock )
           {
            /// Receive data from Other Peer
             recv(nConnectedSock );
    
           }
    
       }
      }
    

5.Убедитесь, что вы одновременно запускаете одноранговое соединение A с B и B с A.
6. Запустите поток прослушивателя до подключения к серверу и одноранговому узлу и используйте единый поток прослушивателя для получения сервера и клиента.

...