Как получить общедоступный c номер порта TcpListener? - PullRequest
1 голос
/ 30 марта 2020

Я пытаюсь напрямую подключить (используя TCP) два устройства, которые находятся за маршрутизаторами, реализующими NAT. Как я вижу, маршрутизаторы транслируют номер порта моих устройств, поэтому порт 13000 (порт, на котором мое приложение прослушивает входящие соединения TCP) на моем компьютере будет иметь совершенно другое значение, как это видно публично. Чтобы соединить два устройства, мне нужно знать, что такое «номер порта пользователя» publi c.

Я создал «сервер рандеву», который доступен публично. Во-первых, я создал TCP-соединение между клиентом A и сервером. Сервер извлек номер порта и передал его другим клиентам, чтобы они могли попытаться подключиться к клиенту А. Но я понял, что когда я создаю новое соединение Tcp с сервером, мое приложение создает новый порт, с которого оно отправляет пакеты. Таким образом, сервер извлекает публичный c порт вновь созданного порта, используемого только для подключения к этому серверу, а не публичный c порт моего слушателя.

Так что я пытаюсь решить его другим способом. Идея такова: я отправляю пакеты UDP с портом источника, установленным в порт TcpListener. Таким образом, теоретически сервер может извлечь из входящего сообщения publi c порт TcpListener (получая исходный порт из дейтаграммы UDP) и передать его другим устройствам в моей сети.

// client side
public void AdvertiseListener(IPAddress address, int port, Guid localDeviceId)
{
    UdpClient client = new UdpClient(ListenerPort); // changing datagram source to port of my TcpListener
    IPEndPoint remoteEP = new IPEndPoint(address, port);

    _logger.LogInformation($"Advertising Tcp port to server at {address.MapToIPv4().ToString()}:{port}");

    byte[] data = localDeviceId.ToByteArray();
    for (int a = 0; a < 10; a++)
    {
        client.Send(data, data.Length, remoteEP);
    }
}


// server side
public void AdvertisementsHandler()
{
    AdvertisementListener = new UdpClient(ListenerPort);

    AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}


private void HandleAdverticement(IAsyncResult ar)
{
    IPEndPoint senderIpEndPoint = new IPEndPoint(0, 0); // source address of incoming datagram
    var receivedData = AdvertisementListener.EndReceive(ar, ref senderIpEndPoint);

    [...]

    _logger.LogInformation($"ADVERTICEMENT RECEIVED, port is {senderIpEndPoint.Port}");

    try
    {
        AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
    }
    catch (Exception e)
    {
        _logger.LogError("Advertiser failed");
    }

}

Проблема заключается в следующем: мой сервер почему-то получает не переведенный номер. senderIpEndPoint в HandleAdverticement равно 13000, что является моим частным номером порта. Похоже, мой роутер, по иронии судьбы, покидает порт, как и на этот раз. У вас есть идеи, что я могу изменить, чтобы решить мою проблему?

...