为了账号安全,请及时绑定邮箱和手机立即绑定

无法使用 UdpClient 捕获接收到的数据报

无法使用 UdpClient 捕获接收到的数据报

C#
浮云间 2022-01-16 15:06:27
我正在尝试向设备发送 UDP 命令并从同一设备接收 UDP 响应。发送工作正常。我可以看到数据报离开(通过 WireShark)。我还可以看到从设备返回的数据报(同样,通过 WireShark)。命令离开和响应接收之间的周转时间约为 15 毫秒。代码Byte[] button_click(Byte[] command) {    // Device exists at a particular IP address and listens for UDP commands on a particular port    IPEndPoint SendingEndpoint = new IPEndPoint(DEVICE_IP, DEVICE_PORT);    // Device always sends from port 32795 to whatever port the command originated from on my machine    IPEndPoint ReceivingEndpoint = new IPEndPoint(DEVICE_IP, 32795);    // Sending client    sendingClient = new UdpClient();    sendingClient.Connect(SendingEndpoint);    // Receiving client    receivingClient = new UdpClient();    receivingClient.Client.ReceiveTimeout = RECEIVE_TIMEOUT; // timeout after 4 seconds    receivingClient.Connect(receivingEndpoint);    // Send command and wait for response    Byte[] response = null;    try    {        sendingClient.Connect(DEVICE_IP, DEVICE_PORT);        sendingClient.Send(command, command.Length);        response = receivingClient.Receive(ref receivingEndpoint);    }    catch (SocketException e)    {        // If we timeout, discard SocketException and return null response    }    return response;}问题我无法在我的应用程序中捕获收到的数据报。当我运行上面的代码时,我得到以下异常:“连接尝试失败,因为连接方在一段时间后没有正确响应,或者连接失败,因为连接的主机没有响应。”StackOverflow 上有类似的帖子,但似乎都没有解决我的情况。而且我已经确认我的数据包没有在我的防火墙中被清除。我究竟做错了什么?
查看完整描述

2 回答

?
慕哥6287543

TA贡献1831条经验 获得超10个赞

我解决了这个问题。解决方案需要两件事:

  1. 发送和接收客户端必须使用相同的本地端口

  2. 发送客户端必须使用IPEndPoint声明的 withIPAddress.Any而接收客户端必须使用IPEndPoint声明的与我的本地机器的确切 IP 地址

代码

// Create endpoints

IPEndPoint DeviceEndPoint = new IPEndPoint(DEVICE_IP, DEVICE_PORT);

IPEndPoint localEndPointAny = new IPEndPoint(IPAddress.Any, LOCAL_PORT); // helps satisfy point 2

IPEndPoint localEndPointExplicit = new IPEndPoint(IPAddress.Parse(GetLocalIPAddress()), LOCAL_PORT);  // helps satisfy point 2

IPEndPoint incomingEndPoint = null; // Later populated with remote sender's info


// Create sending client

UdpClient sendingClient = new UdpClient();

sendingClient.ExclusiveAddressUse = false; // Going to use same port for outgoing and incoming (helps satisfy point 1)

sendingClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // helps satisfy point 1

sendingClient.Client.Bind(localEndPointAny); // Any outgoing IP address will do


// Create receiving client

UdpClient receivingClient = new UdpClient();

receivingClient.Client.ReceiveTimeout = RECEIVE_TIMEOUT; // 4000 milliseconds

receivingClient.ExclusiveAddressUse = false; // Going to use same port for outgoing and incoming (helps satisfy point 1)

receivingClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // helps satisfy point 1

receivingClient.Client.Bind(localEndPointExplicit); // Must explicitly give machine's outgoing IP address

获取本地 IP 地址的代码可以在这里找到。


查看完整回答
反对 回复 2022-01-16
?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

如果您使用 sendClient 来接收,那么您可以获得正确的消息。原因是IP由Host+Port+Protocol组成,当发送点连接到设备并发送消息时,设备接收到Endpoint和与发送Endpoint配对的UDP。当接收客户端尝试接收消息时,由于UDP是Peer to Peer,因此没有任何反应,并且接收客户端的端口必须与发送客户端不同,因此接收客户端什么也得不到。以下是我的示例代码供您参考。


        IPAddress address;

        IPAddress.TryParse("127.0.0.1", out address);

        IPEndPoint recPoint = new IPEndPoint(address, 13154);

        // IPEndPoint sendPoint = new IPEndPoint(address, 9999);

        UdpClient send = new UdpClient(9999);

        send.Connect(recPoint);

        Byte[] response = null;

        Byte[] command = System.Text.Encoding.Default.GetBytes("NO one");

        try

        {

            send.Send(command, command.Length);

            response = send.Receive(ref recPoint);

        }

        catch(Exception ex) {

            Console.WriteLine(ex.ToString());

        }

根据亚历克斯的回答,我更新了一个完整的示例代码以供参考。


using System;

using System.Threading;

using System.Threading.Tasks;

using System.Collections.Concurrent;

using System.Diagnostics;

using System.IO;

using System.Net.Sockets;

using System.Text;

using System.Net;


namespace console

{

    class Program

    {

        static void Main(string[] args)

        {

            IPAddress address;

            IPAddress.TryParse("192.168.14.173", out address);

            IPEndPoint recPoint = new IPEndPoint(address, 13154);

            IPEndPoint recAnyPoint = new IPEndPoint(IPAddress.Any, 13154);

            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.14.174"), 13154);


            // IPEndPoint sendPoint = new IPEndPoint(address, 9999);

            UdpClient send = new UdpClient();

            send.ExclusiveAddressUse = false;

            // no need to use the low level socketoption 

            // send.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

            send.Client.Bind(recAnyPoint);

            send.Connect(ipPoint);

            UdpClient receive = new UdpClient();


            receive.ExclusiveAddressUse = false;

            // receive.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

            receive.Client.Bind(recPoint);

            receive.Connect(ipPoint);

            Byte[] response = null;

            Byte[] command = System.Text.Encoding.Default.GetBytes("NO one");

            try

            {

                send.Send(command, command.Length);

                response = receive.Receive(ref ipPoint);

                Console.WriteLine(System.Text.Encoding.Default.GetString(response));

            }

            catch(Exception ex) {

                Console.WriteLine(ex.ToString());

            }

        }

    }

}


查看完整回答
反对 回复 2022-01-16
  • 2 回答
  • 0 关注
  • 332 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信