【问题标题】:How to access UDP Server using external IP Address如何使用外部 IP 地址访问 UDP 服务器
【发布时间】:2015-04-23 06:50:14
【问题描述】:

我有以下 UDP 服务器在端口 11000 上侦听:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPServer
{
    class Program
    {
        static byte[] dataToSend = new byte[] { 1, 2, 3, 4, 5 };

    // get the ip and port number where the client will be listening on
    static IPEndPoint GetClientInfo()
    {
        // wait for client to send data
        using (UdpClient listener = new UdpClient(11000))
        {
            IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 11000);
            byte[] receive_byte_array = listener.Receive(ref groupEP);

            return groupEP;
        }
    }

    static void Main(string[] args)
    {
        var info = GetClientInfo(); // get client info

        /* NOW THAT WE HAVE THE INFO FROM THE CLIENT WE ARE GONG TO SEND
           DATA TO IT FROM SCRATCH!. NOTE THE CLIENT IS BEHIND A NAT AND
           WE WILL STILL BE ABLE TO SEND PACKAGES TO IT
        */

        // create a new client. this client will be created on a 
        // different computer when I do readl udp punch holing
        UdpClient newClient = ConstructUdpClient(info);

        // send data
        newClient.Send(dataToSend, dataToSend.Length);
    }

    // Construct a socket with the info received from the client
    static UdpClient ConstructUdpClient(IPEndPoint clientInfo)
    {
        var ip = clientInfo.Address.ToString();
        var port = clientInfo.Port;

        // this is the part I was missing!!!!
        // the local end point must match. this should be the ip this computer is listening on
        // and also the port            
        UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Any, 11000));

        // lastly we are missing to set the end points. (ip and port client is listening on)

        // the connect method sets the remote endpoints
        client.Connect(ip, port);

        return client;
    }
}

我还在我的路由器中打开了一个端口,因此当从我的路由器网关地址接收到数据时,它将映射到我在 192.168.1.101:1000 上的主机,如下所示:

我还定义了以下客户端,它在 LAN 上的另一台机器 (192.168.1.108) 上运行:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace UDPClient
{
    class Program
    {
        static void Main(string[] args)
        {
            string ipOfServer = "205.172.111.250";
            int portServerIsListeningOn = 11000;

        // send data to server
        Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        IPAddress send_to_address = IPAddress.Parse(ipOfServer);
        IPEndPoint sending_end_point = new IPEndPoint(send_to_address, portServerIsListeningOn);
        sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);

        // get info
        var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];

        // now wait for server to send data back
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
        byte[] buffer = new byte[1024];
        sending_socket.Receive(buffer); // <----- we can receive data now!!!!!
    }
}

}

请注意 ipOfServer。这是我的外部网关(不是真的,因为我混淆了它,但它不是 192.168.1.101 - 我的 UDP 服务器的内部 IP)。

当我指示客户端发送到 192.168.1.101:11000 的内部 LAN IP 时,UDP Server 连接。

但是,当我使用网关的 IP 地址和端口时,UDP 服务器无法连接。由于我在 NAT 中将端口定向到 192.168.1.101:1000,所以我不确定是什么。

我知道 NAT 设置很好,因为我还有用于 HTTP 的端口 80 和用于 net.tcp 的端口 808,所有这些都可以在任何地方工作,甚至在我的网络之外。

请告诉我我做错了什么。

亲切的问候

【问题讨论】:

    标签: c# .net udp server


    【解决方案1】:

    如果无法访问您的实际网络设置,就很难确切知道出了什么问题。然而,创建一个套接字只是为了接收一些被丢弃的数据,然后创建一个新的套接字然后你“连接”到客户端的方案似乎是错误的。首先,您可能不应该将 Connect() 与 UDP 套接字一起使用,如果您觉得必须,您应该在收到一些数据后连接原始套接字。

    无论如何,您真正需要担心的是客户端方面的事情。您已经将路由器设置为转发服务器的入站数据报,因此服务器应该始终能够在该端口上接收。有问题的是返回给客户的流量;事实是,并非所有路由器都支持这种情况,并且总是需要对 UDP 流量进行端口转发(TCP 流量更容易,因为路由器可以与客户端保持持续的连接)。

    我建议你让服务器更简单——只需创建一个用于接收数据报的套接字(当然不要用using 处理它)。我还建议不要使用Connect(),因为这样做只会不必要地限制服务器。 IE。它将阻止服务器的套接字能够处理多个客户端。如果你真的想做一些针对每个客户端的过滤,一个更好的机制是让服务器始终接收所有数据报,然后检查接收地址本身来决定如何处理数据报。

    【讨论】:

    • 我真的在尝试实现 UDP 打孔,如下所述:en.wikipedia.org/wiki/UDP_hole_punching 我尝试从 Socket 派生并使用本地 IP (192.xxx) 调用 Bind,但仍然没有与外界的连接.
    • 我试过了:this.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.108"), 11000));对网关 IP 地址调用 bind 会抛出异常:请求的地址在其上下文中无效
    • @NickV:您的场景中没有任何内容表明您需要实施“打孔”。该技术通常用于代替在路由器或代理中配置端口转发。它通常涉及每个客户端联系一个公共的第三个服务器,利用 NAT 路由器中有时实现的行为,其中一旦第三个服务器回复一个客户端,另一个客户端也可以发送给第一个客户端和让路由器也转发来自它的流量。不能保证这适用于任何给定的路由器,并且在您明确转发端口时不需要。
    • @NickV:(继续...)您绝对不能绑定到网关的地址。唯一要绑定的合法地址是由本地计算机托管的地址。通常,您只需绑定到 IPAddress.Any,以便套接字可以接收发送到该机器托管的任何 IP 地址的数据报。
    • 谢谢你,彼得,为你的 cmets。然而,这个服务器只是一个更大的系统的一部分,它将包含 P2P 声音和视频。我已经有了 P2P UDP 部分来发送声音和视频。我现在需要结合打孔方法来使 P2P 系统正常工作。我已经考虑过 WCF P2P 以及集中转发方法。我将负载平衡限制在任何给定计算机上不超过 10 个对等点,因此转发声音和视频数据包应该不是什么大问题,但延迟是一个问题。 P2P 首先需要一个 UDP 服务器,其中 NAT 的分机。 IP被发送到每个节点。
    猜你喜欢
    • 2022-11-17
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 2017-01-10
    • 2016-09-23
    • 2016-03-20
    相关资源
    最近更新 更多