【问题标题】:C# Getting the IP Address of the client which the UDP server socket received data fromC#获取UDP服务器套接字从中接收数据的客户端的IP地址
【发布时间】:2018-09-04 10:49:23
【问题描述】:

我有一个很奇怪的问题。我无法找到我的服务器从中接收数据的客户端的 IP 地址。下面是我的 UDP Listener 类。

IPPacketInformation 不包含 IP。我在 EndReceiveMessageFrom 中引用的 clientEndPoint 两者都没有。

当我

Console.Writeline(((IPEndPoint)clientEndPoint).Address); 

我得到了服务器的 IP 地址。我将服务器托管在我自己的机器上,所以我有自己的 IP 地址。当我尝试访问 clientEndPoint.remoteEndPoint 时,它会抛出一个错误,因为套接字未连接(由于是 UDP)。

所以基本上,来自外部 IP 的客户端能够发送数据,但我无法回答客户端,因为我无法检索它的 IP。任何帮助表示赞赏!

public class UdpListener
{
    private Socket s;
    public byte[] ReceiveBuffer = new byte[2048];

    public UdpListener()
    {
        s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
        s.Bind(new IPEndPoint(IPAddress.Any, 36200));
    }

    public void Listen()
    {
        try
        {
            EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
            s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            throw;
        }
    }

    private void Recv(IAsyncResult res)
    {
        try
        {
            Socket receiveSocket = (Socket)res.AsyncState;

            EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
            IPPacketInformation packetInfo;
            SocketFlags flags = SocketFlags.None;
            int udpMessageLength = receiveSocket.EndReceiveMessageFrom(res, ref flags, ref clientEndPoint, out packetInfo);
            byte[] udpMessage = new byte[udpMessageLength];
            Array.Copy(ReceiveBuffer, udpMessage, udpMessageLength);

            Console.WriteLine(
                "{0} bytes received from {1} to {2}",
                ReceiveBuffer,
                clientEndPoint,
                packetInfo.Address
            );

            EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, ((IPEndPoint)receiveSocket.LocalEndPoint).Port);
            s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);

            //Process data
            RaiseDataReceived(new ReceivedDataArgs(packetInfo.Address, ((IPEndPoint)clientEndPoint).Port, udpMessage));
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            throw;
        }
    }

    public delegate void DataReceived(ReceivedDataArgs args);

    public event DataReceived DataReceivedEvent;

    private void RaiseDataReceived(ReceivedDataArgs args)
    {
        DataReceivedEvent?.Invoke(args);
    }
}

我尝试禁用我的防火墙,但没有帮助。我还在路由器上完成了端口转发,因此我可以从外部客户端接收数据。

编辑以澄清问题:

服务器托管在我的机器上,位于公共 IP 214.214.214.214 的 NAT 后面。

客户端是另一台机器,位于另一个具有公共 IP 910.910.910.910 的 NAT 后面。

客户端向服务器发送消息,服务器接收并能够读取内容。服务器获取到客户端的IPEndPoint后,显示的IP为214.214.214.214(服务器的IP,不是客户端

编辑 也许我应该说,在我从 ISP 订购“动态 IP”之前,我无法接收来自外部网络客户端的消息。还是拿不到源的公网IP。

编辑 当使用 Wireshark 并嗅探从外部客户端发送到我的服务器的数据包时,我可以看到它也是错误的 src IP。在下图中,src IP 是我的服务器 IP,而不是发送数据的客户端的 IP。

【问题讨论】:

  • 为什么要收听端口零? IPEndPoint(IPAddress.Any, 0);
  • 我正在侦听端口 36200。如果您的意思是 remoteEndPoint 或 clientEndPoint 端口 0,那么只要收到消息,endPoint 就会被覆盖
  • 你考虑过使用UdpClient吗?
  • 我试过了。结果相同。我也尝试过 Receive、ReceiveFrom、ReceiveAsync。
  • 您确定端口号的overderriding 工作正常吗?我从来没有听说过监听器启动后端口号会发生变化。

标签: c# network-programming udp


【解决方案1】:

几天后,我在路由器、网络上阅读了所有可能的内容并编写了 Receive、ReceiveFrom、ReceiveMessageFrom、BeginReceive、BeginReceiveFrom、BeginReceiveMessageFromReceiveAsync 的不同示例 -我已经解决了我的问题。

我更换了路由器。我现在可以使用非常旧的路由器获取外部客户端的源 IP。我之前使用的路由器是新的 Docsis 3.1。

为什么它适用于旧路由器,我不知道,但由于某种原因,Docsis 3.1 在将 UDP 消息发送到我的机器之前将源 IP 更改为它自己的 IP。

【讨论】:

  • 我感受到了你的痛苦。关于使用 C# 套接字时数据包实际发生的情况,信息量非常有限。不同的答案建议使用“多播”进行通信,但经过几天的故障排除后,您将了解到并非所有路由器都支持 igmp 数据包解析。此外,当您创建 UdpClient 时实际发生了什么,例如它绑定的实际网络接口。或者何时使用 Receive 与 BeginReceive。
【解决方案2】:

通过使用UdpClient 类,您实际上可以在接收消息时检索远程端点。

我使用了类似以下的解决方案来解决此任务:

public void StartServer()
{
    var udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT));
    udpServer.BeginReceive(new AsyncCallback(detectionCallback), udpServer);
}

private void detectionCallback(IAsyncResult ar)
{
    var client = (ar.AsyncState as UdpClient);
    if (client.Client == null) return;

    var endPoint = new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT);
    var bytes = client.EndReceive(ar, ref endPoint);

    Debug.WriteLine($"Detection request from: {endPoint}");
}

【讨论】:

  • 用服务器公共 IP:214.214.214.214 和客户端公共 IP:910.910.910.910 尝试了这个例子。从客户端向服务器发送消息时,服务器上打印的端点包含“214.214.214.214:57650”而不是“910.910.910.910:57650”
  • 客户端公网IP:910.910.910.910?那怎么可能是客户端IP?这不是一个有效的 IP 地址。
  • 这是一个例子,因为我不会提供自己的IP
  • 不幸的是,这是一个幼稚的解决方案。如果在 IPAddress.Any 上创建 UdpClient 选择了错误的网络接口,它将无法提供正确的功能。有些电脑可能有 USB wifi 加密狗,或者有多个网络接口。
猜你喜欢
  • 1970-01-01
  • 2016-01-01
  • 2019-08-28
  • 2011-08-15
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 1970-01-01
  • 2016-06-04
相关资源
最近更新 更多