C# UDP通信方法 C#如何实现UDP Socket编程

11次阅读

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

C# UDP通信方法 C#如何实现UDP Socket编程

UDP通信用 UdpClient 还是 Socket

日常开发中优先用 UdpClient,它封装了底层 Socket 的细节,写法简洁、不易出错;只有需要精细控制(如设置 IP_PKTINFO、绑定到任意接口、复用端口等)时才直接操作 Socket

注意:UdpClient 默认不支持异步接收多个包的并发处理(单次 Receive 阻塞),若需高吞吐或长连接模型,得配合线程/任务或改用 Socket.ReceiveFromAsync

  • UdpClient 构造后自动创建并绑定 Socket,调用 Close()Dispose() 才释放资源
  • 直接用 Socket 时,必须显式调用 Bind(),且协议类型要设为 SocketType.Dgram + ProtocolType.Udp
  • UdpClientClient 属性可拿到底层 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.AnyIPAddress.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_REUSEPORTlinux/macOS)

UDP 没有连接状态,所以抓包看到 SYN/RST 等 TCP 标志位一定不是 UDP 流量;调试时优先用 netstat -uanp(Linux)或 Get-NetUDPEndpoint(PowerShell)确认端口是否真在监听。

text=ZqhQzanResources