导读:本期聚焦于IT小魔仙创作的《C#怎么发送UDP广播?使用UdpClient收发报文完整教程》,敬请观看详情。UDP广播在局域网设备发现、心跳检测等场景里用得非常多,比如扫描网段内的打印机、与嵌入式设备握手等。本文围绕C#环境下如何使用UdpClient实现UDP报文的发送与接收展开,先讲清楚广播地址的构成和255.255.255.255与定向广播的区别,再给出完整的发送端与接收端代码,包括端口复用、异步接收、超时处理这几个容易踩坑的点,最后对比同步与异步两种接收方式的适用场景,帮你快速搭起一套稳定可靠的局域网UDP通信程序。

在局域网通信开发中,UDP广播是一个非常实用的功能,常见于设备发现、服务宣告、心跳检测等场景。比如你写一个上位机程序,需要在启动时自动找到网段内的下位机设备,通常的做法就是向广播地址发一个探测报文,设备收到后回送自己的IP和端口。C#标准库里的UdpClient类把底层Socket操作封装得比较到位,用它实现广播收发比直接操作Socket省事不少。本文从广播地址的原理讲起,逐步给出完整的发送端和接收端实现,并说明几个实际部署中容易出问题的细节。

C#怎么发送UDP广播?使用UdpClient收发报文完整教程

一、先弄明白广播地址是怎么回事

UDP广播本质上是向一个特殊的IP地址发送数据包,这个地址被称为广播地址。最简单粗暴的是受限广播地址255.255.255.255,发到这个地址上的报文会被当前局域网内的所有主机接收,路由器不会把它转发到外网。另一种是定向广播地址,需要根据子网计算得出,比如你的机器IP是192.168.1.100,子网掩码是255.255.255.0,那么定向广播地址就是192.168.1.255。

两者的区别值得注意。255.255.255.255在小网络里用起来最方便,不需要知道本机IP,但它有个限制:部分操作系统或网络设备在多网卡环境下表现不一致,报文可能只从默认路由对应的网卡发出。定向广播则可以明确指定从哪个网段发出去,在多网卡的服务器上更可控,不过使用定向广播时,接收方所在主机的防火墙或路由配置可能需要放行。开发阶段建议先用255.255.255.255跑通流程,遇到多网卡问题再切换到定向广播。

另外一个前提知识是:发送UDP广播前,必须开启Socket的广播权限,对应SocketOptionName.Socket的Broadcast选项。UdpClient提供了一个便捷的EnableBroadcast属性,设置为true即可,否则发送时会抛出SocketException,提示“在其上下文中,该请求的地址无效”。这是新手最常遇到的第一个报错。

二、发送端实现:发送广播报文

发送端的逻辑很直接:创建UdpClient,开启广播权限,把报文转成字节数组,调用Send方法发往广播地址的指定端口即可。下面是完整代码:

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

class UdpBroadcastSender
{
    static void Main()
    {
        // 创建UdpClient并随机绑定一个本地端口
        using (UdpClient sender = new UdpClient())
        {
            // 必须开启广播权限,否则发送会失败
            sender.EnableBroadcast = true;

            // 广播目标地址和端口
            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Broadcast, 9000);

            // 准备要发送的数据
            string message = "DEVICE_DISCOVERY_REQUEST";
            byte[] data = Encoding.UTF8.GetBytes(message);

            try
            {
                int sent = sender.Send(data, data.Length, remoteEP);
                Console.WriteLine($"已发送 {sent} 字节到 {remoteEP}");
            }
            catch (SocketException ex)
            {
                Console.WriteLine("发送失败: " + ex.Message);
            }
        }
    }
}

代码中IPAddress.Parse("255.255.255.255")明确指定了受限广播地址。如果想用定向广播,改成实际的网段广播地址,比如IPAddress.Parse("192.168.1.255")。端口9000是接收方监听的端口,发送方自身使用的本地端口是系统随机分配的,这一点和TCP不同,UDP不需要事先建立连接。

实际项目中更常见的做法是“一发一收”:发送探测报文后,在同一个UdpClient上等待设备的应答。因为应答会回到发送时所用的本地端口,所以复用同一个UdpClient实例即可收到回包。为了避免程序卡死,建议给UdpClient设置接收超时:

sender.Client.ReceiveTimeout = 3000; // 3秒无应答则抛出异常
try
{
    IPEndPoint responder = new IPEndPoint(IPAddress.Any, 0);
    byte[] reply = sender.Receive(ref responder);
    Console.WriteLine($"收到 {responder} 的应答: {Encoding.UTF8.GetString(reply)}");
}
catch (SocketException)
{
    Console.WriteLine("等待应答超时");
}

这里的ref参数是UdpClient.Receive方法的设计特点,调用后该变量会被填充为实际发送方的地址信息,通过它能拿到应答设备的IP和端口,正好满足设备发现场景的需求。

三、接收端实现:监听并响应广播

接收端需要绑定到广播报文的目标端口,也就是发送端使用的9000端口。关键点在于,广播报文会同时送达局域网内所有监听该端口的主机,如果同一台机器上要跑多个接收实例做测试,就必须开启端口共享:

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

class UdpBroadcastReceiver
{
    static void Main()
    {
        UdpClient receiver = new UdpClient();
        // 允许多个进程绑定同一端口,接收广播必须设置
        receiver.Client.SetSocketOption(
            SocketOptionLevel.Socket,
            SocketOptionName.ReuseAddress, true);

        receiver.Client.Bind(new IPEndPoint(IPAddress.Any, 9000));

        Console.WriteLine("开始监听 UDP 9000 端口的广播...");
        while (true)
        {
            IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
            byte[] data = receiver.Receive(ref remote);
            string msg = Encoding.UTF8.GetString(data);
            Console.WriteLine($"来自 {remote}: {msg}");

            // 回送应答,告知对方本机信息
            byte[] ack = Encoding.UTF8.GetBytes("DEVICE_ACK:" + Dns.GetHostName());
            receiver.Send(ack, ack.Length, remote);
        }
    }
}

注意代码里绑定的地址是IPAddress.Any,表示接收发往本机任意网卡的9000端口数据,这是最稳妥的写法。如果不设置ReuseAddress,第二个绑定同一端口的进程会直接抛出“通常每个套接字地址只允许使用一次”的异常。另外应答时直接用接收用的UdpClient回发即可,目标地址就是remote变量里记录的发送方地址。

上面的写法是同步阻塞式接收,Receive方法会一直挂起线程直到有数据到达。对于控制台小程序没问题,但如果放在WinForm或WPF界面程序里,直接在UI线程调用会卡死界面,这时应该放到后台线程,或者改用异步方式。

四、异步接收与注意事项

.NET Framework 4.5以上或.NET Core项目推荐使用ReceiveAsync异步接收,配合async/await写起来非常清爽:

static async Task ReceiveLoopAsync(UdpClient receiver, CancellationToken token)
{
    while (!token.IsCancellationRequested)
    {
        try
        {
            UdpReceiveResult result = await receiver.ReceiveAsync();
            string msg = Encoding.UTF8.GetString(result.Buffer);
            Console.WriteLine($"来自 {result.RemoteEndPoint}: {msg}");
        }
        catch (ObjectDisposedException)
        {
            break; // UdpClient被释放,退出循环
        }
        catch (SocketException)
        {
            // 忽略个别异常继续监听
        }
    }
}

异步方式的好处是不占用线程等待,UI程序里调用也不会卡界面。退出程序时调用receiver.Close(),挂起的ReceiveAsync会抛出ObjectDisposedException,捕获后就能干净地结束循环。

最后提醒几个实际部署中容易忽视的问题。第一,Windows防火墙默认会拦截入站UDP,调试时若收不到报文,先检查防火墙对程序或端口的放行情况,这是排错时最该先确认的一环。第二,UDP不保证送达,设备发现的探测报文建议连续发两三次提高命中率,接收端要做去重处理。第三,报文长度控制在1400字节以内比较安全,超过网络MTU会触发分片,丢包概率明显上升。第四,生产环境别忘了加try-catch包裹网络操作,拔网线、切网络这类异常在SocketException里都会体现,程序要有重试或提示机制。

C# UDP广播UdpClientSocket通信修改时间:2026-09-10 14:02:39

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0910/54065.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。