You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# UDP应用可发送消息但无法接收的问题排查

问题描述

我正在编写一个基于UDP协议的C#小型应用,需要同时实现消息的发送与接收功能。目前应用能正常发送消息,但无法接收消息,通过Wireshark确认服务器已经发出响应消息。

通信流程如下:客户端从随机端口(如55567)向服务器1711端口发送消息,服务器从1711端口回复到该随机端口。我尝试将监听客户端设置为与发送客户端相同的端口时出现异常,猜测应该监听该随机端口而非1711,但尝试基础示例代码后仍无法接收响应。

相关代码如下:

using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace DeviceLinkApp
{
    class Program
    {
        private const int DLPort = 1711;
        private static UdpClient receivingUdpClient;

        static void Main(string[] args)
        {
            BackgroundWorker senderWorker = new BackgroundWorker();
            senderWorker.DoWork += new DoWorkEventHandler(SenderThread);
            senderWorker.RunWorkerAsync();

            // 创建用于读取 incoming 数据的 UdpClient
            receivingUdpClient = new UdpClient(DLPort);

            try
            {
                receivingUdpClient.BeginReceive(new AsyncCallback(recv), null);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.ReadLine();
        }

        // 回调函数
        private static void recv(IAsyncResult res)
        {
            IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 1711);
            byte[] received = receivingUdpClient.EndReceive(res, ref RemoteIpEndPoint);

            // 处理逻辑
            Console.WriteLine(Encoding.UTF8.GetString(received));
            receivingUdpClient.BeginReceive(new AsyncCallback(recv), null);
        }

        private static void SenderThread(object sender, DoWorkEventArgs args )
        {
            UdpClient udpClient = new UdpClient();

            while (true)
            {
                System.Threading.Thread.Sleep(2000);

                Byte[] sendBytes1 = Encoding.ASCII.GetBytes("R/115");
                Byte[] sendBytes2 = Encoding.ASCII.GetBytes("R/103");
                Byte[] sendBytes3 = Encoding.ASCII.GetBytes("R/40");
                try
                {
                    udpClient.Send(sendBytes1, sendBytes1.Length, "192.168.1.164", DLPort);
                    udpClient.Send(sendBytes2, sendBytes2.Length, "192.168.1.164", DLPort);
                    udpClient.Send(sendBytes3, sendBytes3.Length, "192.168.1.164", DLPort);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
    }
}
解决方案

问题核心

当前代码存在两个关键问题:

  1. 发送和接收使用两个独立的UdpClient:发送用的UdpClient未绑定固定端口,系统会分配随机端口;而接收用的UdpClient绑定了1711端口,服务器回复的是发送时的随机端口,因此接收端无法捕获响应。
  2. 接收回调中初始化的RemoteIpEndPoint指定了端口1711,这会限制仅接收来自该端口的消息,但服务器的回复实际来自客户端的随机发送端口,导致无法正确接收。

修复方案

复用同一个UdpClient处理发送和接收:这样发送时使用的端口就是该UdpClient绑定的端口,接收端监听同一个端口即可捕获服务器的回复。具体修改如下:

  1. 全局仅保留一个UdpClient实例,初始化时绑定IPEndPoint.Any(让系统自动分配端口,也可指定固定端口)。
  2. 发送线程直接使用该全局UdpClient发送消息。
  3. 接收回调中,将RemoteIpEndPoint初始化为IPAddress.Any, 0,允许接收来自任意端口的消息。

修改后的代码

using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace DeviceLinkApp
{
    class Program
    {
        private const int DLPort = 1711;
        // 全局复用同一个UdpClient
        private static UdpClient _udpClient;

        static void Main(string[] args)
        {
            // 初始化UdpClient,绑定任意IP和系统分配的端口(也可指定固定端口,如new IPEndPoint(IPAddress.Any, 5000))
            _udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, 0));

            // 启动发送线程
            BackgroundWorker senderWorker = new BackgroundWorker();
            senderWorker.DoWork += SenderThread;
            senderWorker.RunWorkerAsync();

            // 启动异步接收
            try
            {
                _udpClient.BeginReceive(RecvCallback, null);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.ReadLine();
        }

        private static void RecvCallback(IAsyncResult res)
        {
            // 初始化端点为任意IP和端口,用于接收来自服务器的响应
            IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Any, 0);
            byte[] receivedBytes = _udpClient.EndReceive(res, ref remoteEndpoint);

            // 处理接收到的消息
            string receivedMsg = Encoding.UTF8.GetString(receivedBytes);
            Console.WriteLine($"收到来自 {remoteEndpoint} 的消息: {receivedMsg}");

            // 继续监听下一条消息
            _udpClient.BeginReceive(RecvCallback, null);
        }

        private static void SenderThread(object sender, DoWorkEventArgs args)
        {
            while (true)
            {
                System.Threading.Thread.Sleep(2000);

                Byte[] sendBytes1 = Encoding.ASCII.GetBytes("R/115");
                Byte[] sendBytes2 = Encoding.ASCII.GetBytes("R/103");
                Byte[] sendBytes3 = Encoding.ASCII.GetBytes("R/40");
                try
                {
                    // 使用全局UdpClient发送消息到服务器的1711端口
                    _udpClient.Send(sendBytes1, sendBytes1.Length, "192.168.1.164", DLPort);
                    _udpClient.Send(sendBytes2, sendBytes2.Length, "192.168.1.164", DLPort);
                    _udpClient.Send(sendBytes3, sendBytes3.Length, "192.168.1.164", DLPort);
                    Console.WriteLine("消息发送完成");
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
    }
}

额外说明

  • 如果需要客户端使用固定端口发送和接收,只需将UdpClient的初始化改为new UdpClient(new IPEndPoint(IPAddress.Any, 自定义端口)),确保端口未被占用即可。
  • UDP是无连接协议,服务器会根据收到的消息源IP和端口进行回复,因此必须保证发送和接收使用同一个端口(即同一个UdpClient实例)才能捕获回复。

内容的提问来源于stack exchange,提问作者Joonatan Renel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:05:24