前言 --- 一封来自远方的信
小李是一个物联网工程师,他正在构建一个分布式监控系统。系统里有很多传感器节点,它们可能部署在厂房角落、室外机房、甚至是偏远的棚区。主站服务器需要和这些节点 轻量、快速、可靠 地通信。TCP 有连接开销、建立慢;而 UDP 轻便、高效,却对丢包敏感。幸运的是,TouchSocket 提供了
UdpSession组件,它就像一个灵活的邮差,能在网络密林中穿梭,传递消息。
一、什么是 UdpSession?
UdpSession 是 TouchSocket 提供的一个基础 UDP 通信组件。它属于 TouchSocket.Sockets 命名空间,由 TouchSocket.dll 提供。([TouchSocket][1])
它既可以作为 UDP 服务(Server) ,也可以作为 UDP 客户端(Client)。在许多场景中,它是最轻量、最基础的 UDP 通信构件。([TouchSocket][1])
二、核心特点 --- 为什么选择 UdpSession?
UdpSession 有几个非常吸引人的特性:
- 简单易用:API 直观,非常适合快速构建 UDP 通信。 ([TouchSocket][1])
- 多线程重叠 I/O:高并发下依然高效。 ([TouchSocket][1])
- 内存池支持:减少频繁分配 / 释放内存的开销。 ([TouchSocket][1])
- 高性能:适合高频消息场景。 ([TouchSocket][1])
- 支持组播 (Multicast) 和广播 (Broadcast):灵活构建不同 UDP 通信模型。 ([TouchSocket][2])
- 插件扩展机制:可以在收到数据时插入插件逻辑 (IUdpReceivedPlugin)。 ([TouchSocket][1])
- 跨平台:适配多种 .NET 平台。 ([TouchSocket][1])
三、典型应用场景
想象以下这些场景:
- 物联网设备通信:主站与多个远程节点之间发送心跳、状态或控制命令。
- 组播消息:多个客户端加入一个组播组 (Multicast),一起接收组播数据。
- 广播场景:广播消息给网络上的所有节点(或某子网),例如发现 / 配置阶段。
- 实时监控:对时延敏感,但对部分丢包可容忍的状态更新。
这些场景非常符合 UdpSession 的能力。
四、如何使用 UdpSession ------ 从 "开启邮件站" 到 "发送信件"
下面通过一个故事 + 示例代码说明如何使用 UdpSession。
4.1 启动一个 UDP "小站"(Server)
小李决定在服务器端运行一个 UdpSession,接收所有传感器节点发来的状态消息:
csharp
var udpService = new UdpSession();
// 收到数据时触发
udpService.Received = (session, e) =>
{
// e.ByteBlock 是接收到的数据
string msg = e.ByteBlock.ToString();
Console.WriteLine($"收到来自 {e.EndPoint} 的消息:{msg}");
return EasyTask.CompletedTask;
};
// 配置监听端口 (例如 7789)
udpService.Setup(new TouchSocket.Core.TouchSocketConfig()
.SetBindIPHost(new TouchSocket.Core.IPHost(7789)));
udpService.Start();
Console.WriteLine("UDP 服务已启动,等待接收消息 ...");
这里:
SetBindIPHost用来指定本地要绑定 (监听) 的端口。([TouchSocket][1])Start()启动 UDP 会话。([TouchSocket][1])
4.2 作为客户端发送 / 接收 --- 小站之外的小邮差
在某个边缘设备 (或控制端),小李也可以用 UdpSession 作为客户端:
csharp
var udpClient = new UdpSession();
udpClient.Setup(new TouchSocket.Core.TouchSocketConfig()
// 绑定一个本地端口 (可以选 0,让系统分配)
.SetBindIPHost(new TouchSocket.Core.IPHost(7788)));
udpClient.Start();
// 假设主站地址是 192.168.1.100:7789
var remoteEP = new System.Net.IPEndPoint(
System.Net.IPAddress.Parse("192.168.1.100"), 7789);
string text = "SensorStatus: OK";
byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
await udpClient.SendAsync(remoteEP, data, 0, data.Length);
Console.WriteLine("已发送状态到主站");
在客户端模式下,如果不设置 SetBindIPHost,那么这个 UdpSession 可能无法接收数据 。官方文档提醒:如果你不知道该绑定哪个端口,可以绑定到 0 端口 (系统会给一个空闲端口)。([TouchSocket][1])
五、接收数据:委托 vs 插件
UdpSession 提供两种方式接收数据:
5.1 通过 Received 委托
像上面示例那样,直接给 Received 属性赋值一个回调。这是最简单直观的方式。([TouchSocket][1])
5.2 使用 插件 (Plugin)
如果业务比较复杂,或者你想把 "业务处理 / 校验 /日志 /过滤" 和底层接收逻辑分离,可以用插件机制。
例如,定义一个插件类:
csharp
public class MyUdpReceivePlugin : PluginBase, TouchSocket.Sockets.IUdpReceivedPlugin
{
public async Task OnUdpReceived(IUdpSession session, UdpReceivedDataEventArgs e)
{
string msg = e.ByteBlock.ToString();
Console.WriteLine($"[插件] 收到消息:{msg} 来自 {e.EndPoint}");
// 继续下一个插件 / 默认处理
await e.InvokeNext();
}
}
然后在配置中注册这个插件:
csharp
var udpService = new UdpSession();
udpService.Setup(new TouchSocket.Core.TouchSocketConfig()
.SetBindIPHost(new TouchSocket.Core.IPHost(7789))
.ConfigurePlugins(p => p.Add<MyUdpReceivePlugin>())
);
udpService.Start();
这样,插件可以在接收到数据时插入你的逻辑 (校验 / 日志 /业务),更灵活。([TouchSocket][1])
六、发送数据 --- 灵活策略
UdpSession 支持多种发送方式:
-
发送到指定地址
你可以指定
EndPoint,向任意目标发送:csharpawait udpSession.SendAsync(remoteEP, buffer, offset, length);([TouchSocket][1])
-
发送到默认地址
如果你在配置里设置了
RemoteIPHost(远程默认地址),可以用不带EndPoint的SendAsync:csharpawait udpSession.SendAsync(buffer, 0, buffer.Length);这种方式在客户端角色时非常有用。([TouchSocket][1])
-
响应接收到的数据源
当你在
Received回调或插件里处理数据时,可以取到e.EndPoint(客户端发来的地址),然后回复:csharpawait session.SendAsync(e.EndPoint, responseBytes, 0, responseBytes.Length);这样可以原路返回给发送方。([TouchSocket][1])
七、进阶玩法 --- 组播与广播 (Multicast / Broadcast)
小李为了让多个节点同时监听某些命令 (例如"全网同步时间" 或 "广播配置命令"),决定使用组播或广播功能:
- 广播 (Broadcast) :通过设置
UseBroadcast,UdpSession 支持广播。([TouchSocket][2]) - 组播 (Multicast) :启动后,通过
JoinMulticastGroup(...)加入一个组播组。这样加入该组的多个 UdpSession 实例都能接收到相同的数据包。([TouchSocket][2])
广播 / 组播非常适合 "一对多" 通信。
八、小李的真实场景:构建健康检查机制
结合他的物联网系统,小李做了这样一个机制:
- 所有节点 (UDP 客户端) 向主站周期性发送 "心跳包" (Heartbeat),内容是节点 ID 和状态。
- 主站 (UDP 服务) 收到心跳后,用插件记录日志 (比如记录节点最后在线时间)。
- 主站 每隔一段时间广播一个 "检查配置版本" 的广播消息 (Broadcast),告诉所有节点检查是否需要下载新配置。
- 节点 收到广播后,如果配置版本落后,就向主站发一个 "请求配置" 消息。
借助 UdpSession,小李的机制轻量、高效,而且非常灵活。
九、使用提醒与注意事项
- 虽然 UDP 轻量,但不可靠:可能丢包、乱序。业务逻辑需要考虑重发、确认机制。
- 绑定端口:如果你作为客户端通信,并且希望接收数据,一定要绑定合适的本地端口 (或设置为 0 让系统分配)。 ([TouchSocket][1])
- 插件顺序:使用多个
IUdpReceivedPlugin时,插件的注册顺序决定调用顺序。 - 内存池:利用好内存池可以大幅降低 GC 和内存分配压力。
- 多播、防火墙:如果使用组播 / 广播,要注意网络设备 (路由器、交换机) 是否支持组播 /广播,以及防火墙规则。
十、小结 --- 为什么推荐 UdpSession
- 轻量、基础:UdpSession 是最基础、最简单的 UDP 会话组件。
- 高性能 + 低开销:支持内存池、多线程重叠 IO。
- 灵活通信模型:单播、广播、组播都能覆盖。
- 插件架构:可以在接收阶段插入业务逻辑 (日志、验证、转发等)。
- 跨平台:.NET 多平台下可用,非常适合物联网 /分布式系统。