Перфорирование отверстий TCP
Я пытаюсь реализовать перфорирование отверстий TCP с помощью сокета Windows с помощью инструментальной цепочки mingw. Я думаю, что этот процесс прав, но дыра, похоже, не воспринимается. Я использовал этот в качестве справочника.
- A и B подключиться к серверу S
- S отправляет на A, B маршрутизатор IP + порт, к которому он привык подключаться к S
- S делает то же самое для B
- A запустите 2 потока:
- Один поток пытается подключиться к маршрутизатору B с информацией, отправленной S
- Другой поток ожидает входящего соединения на том же порту, который используется для подключения к его маршрутизатору, когда он подключен к S
- B делает то же самое
У меня нет проблем в коде, который я думаю с тех пор:
- A и B получают друг друга ip и порт для использования
- Они оба слушают порт, который они использовали для подключения к своему маршрутизатору, когда они связались с сервером.
- Они оба подключаются к правильному ip и порту, но получают тайм-аут (ошибка кода
10060
)
Я что-то упустил?
EDIT:. С помощью обработчика процессов я вижу, что одному из клиентов удалось установить соединение с одноранговым узлом. Но коллега не считает, что соединение должно быть сделано.
Вот что я захватил с 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 Hole Punching, чтобы открыть отверстия!
Ответы
Ответ 1
Начало 2 потока:
Один поток пытается подключиться к маршрутизатору B с информацией, отправленной S
Другой поток ожидает входящего соединения на том же порту, который используется для подключения к его маршрутизатору, когда он подключен к S
Вы не можете сделать это с помощью двух потоков, так как это всего лишь одна операция. Каждое TCP-соединение, выполняющее исходящее соединение, также ожидает входящего соединения. Вы просто вызываете "connect", и вы отправляете исходящие SYN для соединения и ожидания входящих SYN для соединения.
Однако вам может потребоваться закрыть соединение с сервером. Вероятно, ваша платформа не позволяет вам устанавливать TCP-соединение из порта, если у вас уже установлено соединение с тем же портом. Так же, как вы начинаете перфорирование отверстий TCP, закройте соединение с сервером. Привяжите новый TCP-сокет к тому же порту и вызовите connect
.
Ответ 2
Простое решение для перехода на NAT-маршрутизаторы - это сделать ваш трафик, следуя протоколу, что ваш NAT уже имеет алгоритм пересылки, например FTP.
Ответ 3
-
Использовать Wireshark для проверки запроса соединения tcp (трехсторонний процесс Handhsake) идет правильно.
-
Убедитесь, что поток Listener имеет функцию select() для демпплексирования дескриптора.
-
sockPeerConect (сокет, используемый для подключения другого однорангового узла) - это FD_SET() в потоке прослушивателя.
-
Убедитесь, что вы проверяете
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. Запустите тему прослушивателя перед подключением к серверу и одноранговому узлу и получите один поток прослушивателя для приема сервера и клиента.
Ответ 4
не каждый маршрутизатор поддерживает штамповку отверстий tcp, пожалуйста, ознакомьтесь со следующей бумагой, которая подробно объясняет:
Одноранговая связь через трансляторы сетевых адресов