0

我有一个将数据(服务器)发送到 UDP 客户端的应用程序。只要我知道客户端的目标地址,它就可以在同一台计算机上完美运行,并且可以在 LAN 上运行。但是,当我通过 Internet 执行此操作时,它不再起作用,因为它没有目标计算机的地址。这是服务器代码:

public ServerSender(String address, Int32 port, int TTL)
{
  m_Address = address;
  m_Port = port;
  m_TTL = TTL;

  Init();
}

private Socket m_Socket;
private IPEndPoint m_EndPoint;
private String m_Address;
private Int32 m_Port;
private Int32 m_TTL;


private void Init()
{
  IPAddress destAddr = IPAddress.Parse(m_Address);

  m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 

  m_EndPoint = new IPEndPoint(destAddr, m_Port);     
}

public void SendBytes(Byte[] bytes)
{
  m_Socket.SendTo(bytes, 0, bytes.Length, SocketFlags.None, m_EndPoint);
}

这是客户端:

    public void Connect(string strAddress, int port)
    {
        m_Address = IPAddress.Parse(strAddress);
        m_Port = port;

        m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Multicast Socket

        m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);

        m_EndPoint = new IPEndPoint(m_Address, m_Port);

        m_Socket.Bind(m_EndPoint);

        m_Socket.Connect(m_EndPoint);

        IsConnected = true;

        this.DoRead();
    }

    private void DoRead()
    {
        try
        {
            m_Socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), m_Socket);
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }

显然,服务器需要监听远程连接,客户端需要连接到服务器。我认为我可以获取远程地址,然后在 SendBytes 方法中发送到远程端点。我尝试了许多不同的异步服务器示例,它们都会导致各种错误。是否有任何简单的方法可以更改此代码以允许它通过 Internet 连接到远程主机?谢谢

4

1 回答 1

1

总结/详细说明一下评论:

  • 您有一个具有公共 IP 的主机,即直接连接到 inet(您的“服务器”)
  • 您有一个没有公共 IP 的主机,即通过某些网关/防火墙连接到 inet ...(您的“客户端”)

由于我不知道你对网络了解多少:TCP / UDP数据包包装在IP数据包中。IP 处理 IP 地址,TCP 和 UDP 知道端口,但是:TCP 端口 1 和 UDP 端口 1 是不同的东西!

您的网络设置可能如下所示,带有一些示例 IP:

|--------|  47.46.43.42              |---------|192.168.0.1       |--------|
| Server |======== The INET =========| Gateway |==================| Client |
|--------|               81.82.83.84 |---------|     192.168.0.100|--------|

这里的网关是您的“路由器”。

您的客户端将被配置为将任何不属于本地 LAN 的流量发送到网关(如果您能够从客户端浏览网站,则配置正确)。

再次注意:如果目标 IP 属于“他们的”网络,网络设备会将 IP 数据包传递给正确的接收者。如果目标 IP 未知,他们将不会交付给任何人。

如果您的客户端尝试向您的服务器端口 1 发送一个 UDP 数据包,它将向网关发送一个包含目标 IP 47.46.43.42 和源 IP 192.168.0.100 的 IP 数据包,以及目标端口 1 和它的端口用于发送数据包(假设端口 2)。网关接收数据包,查看目标 IP 并将 IP 数据包的内容作为新的 IP 数据包发送(目标 47.46.43.42:1,源 81.82.83.84)。它必须使用另一个 UDP 端口进行发送,比如说 15。这里的关键是:它还记得它从 192.168.0.100 端口 2 向 47.46.43.42 端口 1 发送了一个数据包,它自己的端口 15。每当一个 UDP 数据包到达在来自 47.46.43.42 的端口 15 上,它可以假设它是一些应该转发到 192.168.0.100 端口 2 的回复。

然后如果服务器收到数据包,它看到的只是(目标 IP 47.46.43.42:1,源 IP 81.82.83.84:83:15)。如果它想发回一个答案,它将发送一个带有(dest 81.82.83.84:15,source 47.46.43.42:1)的IP数据包。请注意,服务器仅“看到”网关,而不是您的客户端!网关接收到数据包,回忆起它刚刚发送了一个 IP 数据包(dest 47.46.43.42:1,source 192.168.0.100:2),假设 IP 数据包是某种应答,并发送一个新的 IP 数据包(dest 192.168 .0.100:2,源 47.46.43.42:1) 以及从服务器接收到您的客户端的内容。

请特别注意,这只有效,因为网关从客户端收到了一个数据包,并从中了解到 192.168.0.100 和 81.82.83.84 '相互交谈'。正因为如此,它才知道如何处理来自您服务器的数据包!

现在让我们反过来试试。有两种可能的情况:

  1. 服务器知道您的客户端的 IP (192.168.0.100) 。回想一下,互联网上的任何设备都不知道这个 IP,因此如果它发出一个 IP 数据包(目标 192.168.0.100,源 81.82.83.84),它不会到达网关,因为到达网关的唯一数据包是那些目标 IP 为 47.46.43.42 。这个选项永远不会起作用。

  2. 服务器知道网关的 IP 并发送一个 IP 数据包(目标 47.46.43.42,源 81.82.83.84)。此数据包将到达网关。但是网关应该如何处理它呢?它从不记得来自 IP 81.82.83.84 的数据包可能应该转发到您的客户端。网关学习的唯一方法是客户端首先向您的服务器发送数据包。此选项也不起作用。

因此,服务器只知道客户端的 IP 是不够的但网关需要了解您的服务器和客户端之间的“对话”。并且您的网关的工作方式要求客户端首先发送一个数据包,准确地使用您想要进一步使用的发送端口。如果您的服务器应该向您的客户端发送 UDP 端口 2,则客户端必须首先从 UDP 端口 2 向服务器发送数据包。

您的网关所做的是NATTING,您最好阅读一下它。

但是,我假设您的网络有一些标准设置。这很可能,但从技术上讲,它可能完全不同,也许您的网关充当防火墙,也部分阻止传出流量,也许您的服务器也配置为使用您的网关作为网关(很奇怪,但在技术上是可能的)。

因此,离线故障排除很困难,如果我不能在这里为您的具体问题提供解决方案(TM),我很抱歉

PS:您可能想知道为什么您的客户端可以使用错误的目标 IP 向网关发送数据包,而您的服务器却不能。这与以下事实有关,即在以太网层上,您的 LAN 是单个网络,而 Internet 不是...

于 2018-08-21T21:36:56.410 回答