如何获取 TcpListener 的公共端口号?

Posted

技术标签:

【中文标题】如何获取 TcpListener 的公共端口号?【英文标题】:How to get public port number of TcpListener? 【发布时间】:2020-07-11 05:11:31 【问题描述】:

我正在尝试直接连接(使用 TCP)实现 NAT 的路由器后面的两个设备。如我所见,路由器正在转换我设备的端口号,因此我的计算机上的端口 13000(我的应用程序正在侦听传入 TCP 连接的端口)将具有与公开看到的完全不同的值。为了连接两个设备,我需要知道监听器的“公共端口号”是什么。

我创建了公开可用的“集合服务器”。首先,我在客户端 A 和服务器之间创建了 TCP 连接。服务器提取端口号并将其传递给其他客户端,以便他们可以尝试连接到客户端 A。但我意识到,当我与服务器创建新的 Tcp 连接时,我的应用程序会创建新的端口来发送数据包。因此,服务器提取新创建的端口的公共端口,仅用于连接到该服务器,而不是我的侦听器的公共端口。

所以我正在尝试以其他方式解决它。这个想法是:我正在发送源端口设置为 TcpListener 端口的 UDP 数据包。这样,理论上,服务器可以从 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");
    


问题是:我的服务器由于某种原因收到未翻译的号码。 HandleAdverticement 中的 senderIpEndPoint 等于 13000,这是我的私有端口号。具有讽刺意味的是,我的路由器似乎这次离开了端口。你有什么想法可以改变什么来解决我的问题吗?

【问题讨论】:

有什么原因不能在路由器上使用端口转发? @PatrickMcvay 是的,我希望我的应用在我无法访问路由器设置的网络上运行。 我相信你已经想到了这一点,但是你是否尝试过使用套接字而不是 UdpClient 呢?文档docs.microsoft.com/en-us/dotnet/framework/network-programming/… 【参考方案1】:

您的TcpListener 没有公共端口号。如果路由器正在使用 NAT 沿途更改您的源端口号,您的应用程序将不知道它。这就是为什么要向公众提供服务时需要端口转发的原因。

您可能正在寻找的是所谓的TCP hole punching。但在大多数情况下,这仍然需要您拥有可以让两个位置交换其公共端点信息的公共第三方公共服务。

或者Universal Plug and Play (UPnP) 可能允许您请求路由器自动进行端口转发。但这不是我自己做过的事情。

【讨论】:

以上是关于如何获取 TcpListener 的公共端口号?的主要内容,如果未能解决你的问题,请参考以下文章

TcpListener 类

wcf客户端怎么获取自身使用的端口号?

如果我们在没有端口号的浏览器中键入www.domainname.com,如何删除端口号后跟域名如www.domainname.com:49200

如何获取当前在android中活动的wifiNetwork的端口号

如何使用 jQuery 从 URL 中获取端口号?

如何使用 jQuery 从 URL 中获取端口号?