日常开发优先用UdpClient,简洁安全;需精细控制时才用Socket;注意Connect后无法接收、发送超长静默截断、Receive阻塞需异步处理,防火墙和端口复用是常见坑点。

UDP通信用 UdpClient 还是 Socket?
日常开发中优先用 UdpClient,它封装了底层 Socket 的细节,写法简洁、不易出错;只有需要精细控制(如设置 IP_PKTINFO、绑定到任意接口、复用端口等)时才直接操作 Socket。
注意:UdpClient 默认不支持异步接收多个包的并发处理(单次 Receive 阻塞),若需高吞吐或长连接模型,得配合线程/任务或改用 Socket.ReceiveFromAsync。
-
UdpClient构造后自动创建并绑定Socket,调用Close()或Dispose()才释放资源 - 直接用
Socket时,必须显式调用Bind(),且协议类型要设为SocketType.Dgram+ProtocolType.Udp -
UdpClient的Client属性可拿到底层Socket实例,用于做高级配置(如SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true))
发送 UDP 包:UdpClient.Send 的关键参数
发送前不用手动指定目标 IP 端口——UdpClient 支持两种模式:一种是构造时绑定本地端口(用于接收),发送时用 Send(byte[], int, IPEndPoint) 显式传目标地址;另一种是用 Connect(IPEndPoint) 后直接调用 Send(byte[], int),此时目标地址被“固定”,后续所有 Send 都发往该地址。
容易踩的坑:Connect() 后不能再接收其他地址的数据(底层 Socket 被限制为“已连接”状态),且 Receive() 会抛 SocketException(错误码 10057)。
- 目标
IPEndPoint必须含有效 IPv4/IPv6 地址和非零端口,IPAddress.Any或IPAddress.IPv6Any是非法目标地址 - 发送缓冲区大小受系统 UDP 缓冲区限制(通常 64KB 左右),超长数据会被静默截断,不报错也不抛异常
- 无连接特性意味着发送成功 ≠ 对方收到,也无重传、确认机制
接收 UDP 包:如何避免 Receive 阻塞主线程?
UdpClient.Receive 是同步阻塞调用,直接放在 UI 线程或主循环里会导致卡死。正确做法是用单独线程、Task.Run 或基于 SocketAsyncEventArgs 的异步模型。
最简可行方案是启动一个后台任务持续接收:
var client = new UdpClient(8080);
_ = Task.Run(async () =>
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var result = await client.ReceiveAsync();
Console.WriteLine($"Received {result.Buffer.Length} bytes from {result.RemoteEndPoint}");
}
catch (ObjectDisposedException) { break; }
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.Interrupted) { break; }
}
});
注意:UdpClient 不提供原生 ReceiveAsync(.NET 6+ 才有),旧版本必须用 BeginReceive/EndReceive 或转到底层 Socket 调用 ReceiveFromAsync。
防火墙与端口绑定常见失败原因
运行时提示“通常每个套接字地址(协议/网络地址/端口)只允许使用一次”(错误码 10048),大概率是端口被占用或未设 ReuseAddress;提示“由于目标计算机积极拒绝,无法连接”(10061),通常是目标机器没开监听,或 Windows 防火墙拦截了入站 UDP 流量。
- 绑定
0.0.0.0:8080表示监听本机所有 IPv4 接口,但 Windows 默认阻止外部访问,需在防火墙中放行该端口(入站规则) - 用
IPAddress.Loopback(即127.0.0.1)只能收本机发的包,跨机器通信必须用实际网卡 IP 或IPAddress.Any - 多个进程不能同时
Bind到同一端口,除非都设置了SocketOptionName.ReuseAddress且至少一个启用了SO_EXCLUSIVEADDRUSE(Windows)或SO_REUSEPORT(Linux/macOS)
UDP 没有连接状态,所以抓包看到 SYN/RST 等 TCP 标志位一定不是 UDP 流量;调试时优先用 netstat -uanp(Linux)或 Get-NetUDPEndpoint(PowerShell)确认端口是否真在监听。











