UDP(User Datagram Protocol)是一种无连接的传输层协议,以其低延迟、高效率的特点在实时通信、游戏、流媒体、物联网等领域得到广泛应用。本文介绍如何在 C#中实现 UDP 网络编程,涵盖从基础概念到实际应用。
UDP 协议基础 UDP vs TCP 对比
特性
UDP
TCP
连接性
无连接
面向连接
可靠性
不保证送达
可靠传输
速度
快速
相对较慢
开销
低开销
高开销
数据完整性
不保证顺序
保证顺序
适用场景
实时通信、广播
文件传输、Web
UDP 应用场景
在线游戏 - 位置同步、状态更新
流媒体 - 音频、视频实时传输
服务发现 - 局域网设备发现
物联网 - 传感器数据采集
即时通讯 - 语音通话、视频会议
监控系统 - 实时数据收集
基础 UDP 实现 单播 UDP 通信 单播是最常见的 UDP 通信方式,一对一的数据传输。
UDP 服务器实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 public class UdpServer : IDisposable { private readonly UdpClient _udpServer; private readonly IPEndPoint _localEndPoint; private readonly CancellationTokenSource _cancellationTokenSource; private bool _isRunning = false ; private bool _disposed = false ; public UdpServer (int port ) { _localEndPoint = new IPEndPoint(IPAddress.Any, port); _udpServer = new UdpClient(); _cancellationTokenSource = new CancellationTokenSource(); _udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true ); _udpServer.Client.Bind(_localEndPoint); } public async Task StartAsync () { if (_isRunning) return ; _isRunning = true ; Console.WriteLine($" UDP服务器启动,监听端口: {_localEndPoint.Port} " ); try { while (!_cancellationTokenSource.Token.IsCancellationRequested) { var result = await _udpServer.ReceiveAsync(_cancellationTokenSource.Token); _ = Task.Run(async () => await ProcessReceivedData(result), _cancellationTokenSource.Token); } } catch (OperationCanceledException) { Console.WriteLine(" UDP服务器已停止" ); } catch (Exception ex) { Console.WriteLine($" UDP服务器异常: {ex.Message} " ); } finally { _isRunning = false ; } } private async Task ProcessReceivedData (UdpReceiveResult result ) { try { var clientMessage = Encoding.UTF8.GetString(result.Buffer); var clientEndPoint = result.RemoteEndPoint; var receiveTime = DateTime.Now; Console.WriteLine($"[{receiveTime:HH:mm:ss.fff} ] 收到来自 {clientEndPoint} 的消息: {clientMessage} " ); var response = await ProcessMessage(clientMessage, clientEndPoint); if (!string .IsNullOrEmpty(response)) { await SendResponseAsync(response, clientEndPoint); } } catch (Exception ex) { Console.WriteLine($" 处理UDP消息时发生错误: {ex.Message} " ); } } private async Task<string > ProcessMessage (string message, IPEndPoint clientEndPoint ) { await Task.Delay(50 ); var serverInfo = GetServerInfo(); return message.ToLower() switch { "ping" => "pong" , "time" => DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff" ), "info" => $"服务器信息: {serverInfo} " , "echo" => $"Echo: {message} " , _ => $"服务器已收到消息: {message} | 服务器IP: {serverInfo} | 时间: {DateTime.Now:HH:mm:ss.fff} " }; } private async Task SendResponseAsync (string response, IPEndPoint clientEndPoint ) { try { var responseBytes = Encoding.UTF8.GetBytes(response); await _udpServer.SendAsync(responseBytes, responseBytes.Length, clientEndPoint); Console.WriteLine($" 向 {clientEndPoint} 发送响应: {response} " ); } catch (Exception ex) { Console.WriteLine($" 发送响应失败: {ex.Message} " ); } } private string GetServerInfo () { try { var localIp = IPProvider.GetRealIPv4(); var hostName = Environment.MachineName; return $"{hostName} ({localIp} )" ; } catch { return "Unknown" ; } } public void Stop () { if (!_isRunning) return ; Console.WriteLine(" 正在停止UDP服务器..." ); _cancellationTokenSource.Cancel(); } public void Dispose () { if (!_disposed) { Stop(); _cancellationTokenSource?.Dispose(); _udpServer?.Dispose(); _disposed = true ; } } }
UDP 客户端实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 public class UdpClient : IDisposable { private readonly UdpClient _udpClient; private readonly IPEndPoint _serverEndPoint; private bool _disposed = false ; public UdpClient (string serverAddress, int serverPort ) { _serverEndPoint = new IPEndPoint(IPAddress.Parse(serverAddress), serverPort); _udpClient = new UdpClient(); _udpClient.Client.ReceiveTimeout = 5000 ; } public async Task<string > SendMessageAsync (string message ) { try { var messageBytes = Encoding.UTF8.GetBytes(message); var sentBytes = await _udpClient.SendAsync(messageBytes, messageBytes.Length, _serverEndPoint); Console.WriteLine($" 向 {_serverEndPoint} 发送消息: {message} ({sentBytes} 字节)" ); var response = await _udpClient.ReceiveAsync(); var responseMessage = Encoding.UTF8.GetString(response.Buffer); Console.WriteLine($" 收到响应: {responseMessage} " ); return responseMessage; } catch (Exception ex) { Console.WriteLine($" 发送消息失败: {ex.Message} " ); return null ; } } public async Task SendBatchMessagesAsync (int count = 10 ) { Console.WriteLine($" 开始批量发送 {count} 条消息..." ); var tasks = new List<Task>(); var stopwatch = Stopwatch.StartNew(); for (int i = 1 ; i <= count; i++) { var message = $"Test message #{i} from {Environment.MachineName} " ; tasks.Add(SendMessageAsync(message)); if (i % 5 == 0 ) { await Task.Delay(100 ); } } await Task.WhenAll(tasks); stopwatch.Stop(); Console.WriteLine($" 批量发送完成,耗时: {stopwatch.ElapsedMilliseconds} ms" ); } public void Dispose () { if (!_disposed) { _udpClient?.Dispose(); _disposed = true ; } } }
UDP 广播通信 广播允许向网络中的所有设备发送消息,常用于服务发现和网络公告。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 public class UdpBroadcastServer : IDisposable { private readonly UdpClient _udpServer; private readonly int _serverPort; private readonly CancellationTokenSource _cancellationTokenSource; private bool _isRunning = false ; public UdpBroadcastServer (int port ) { _serverPort = port; _udpServer = new UdpClient(); _cancellationTokenSource = new CancellationTokenSource(); _udpServer.Client.Bind(new IPEndPoint(IPAddress.Any, _serverPort)); _udpServer.EnableBroadcast = true ; _udpServer.Client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true ); } public async Task StartAsync () { if (_isRunning) return ; _isRunning = true ; Console.WriteLine($" UDP广播服务器启动,监听端口: {_serverPort} " ); Console.WriteLine("可以接收单播和广播消息" ); try { while (!_cancellationTokenSource.Token.IsCancellationRequested) { var result = await _udpServer.ReceiveAsync(_cancellationTokenSource.Token); _ = Task.Run(async () => await ProcessBroadcastMessage(result), _cancellationTokenSource.Token); } } catch (OperationCanceledException) { Console.WriteLine(" UDP广播服务器已停止" ); } catch (Exception ex) { Console.WriteLine($" UDP广播服务器异常: {ex.Message} " ); } finally { _isRunning = false ; } } private async Task ProcessBroadcastMessage (UdpReceiveResult result ) { try { var clientMessage = Encoding.UTF8.GetString(result.Buffer); var clientEndPoint = result.RemoteEndPoint; var receiveTime = DateTime.Now; bool isBroadcast = IsBroadcastAddress(clientEndPoint.Address); string messageType = isBroadcast ? "广播" : "单播" ; Console.WriteLine($"[{receiveTime:HH:mm:ss.fff} ] 收到{messageType} 消息" ); Console.WriteLine($" 来源: {clientEndPoint} " ); Console.WriteLine($" 内容: {clientMessage} " ); await HandleBroadcastRequest(clientMessage, clientEndPoint, isBroadcast); } catch (Exception ex) { Console.WriteLine($" 处理广播消息时发生错误: {ex.Message} " ); } } private async Task HandleBroadcastRequest (string message, IPEndPoint clientEndPoint, bool isBroadcast ) { if (isBroadcast) { if (message.ToLower().Contains("discover" ) || message.ToLower().Contains("who" )) { var deviceInfo = GetDeviceInfo(); await SendResponse(deviceInfo, clientEndPoint); } else { Console.WriteLine(" 广播消息,不发送响应" ); } } else { var localIp = IPProvider.GetRealIPv4(); var response = $"服务器已收到消息: {message} ;服务器IP: {localIp} " ; await SendResponse(response, clientEndPoint); } } private async Task SendResponse (string response, IPEndPoint clientEndPoint ) { try { var responseBytes = Encoding.UTF8.GetBytes(response); await _udpServer.SendAsync(responseBytes, responseBytes.Length, clientEndPoint); Console.WriteLine($" 已向 {clientEndPoint} 发送响应" ); } catch (Exception ex) { Console.WriteLine($" 发送响应失败: {ex.Message} " ); } } private string GetDeviceInfo () { var deviceInfo = new { DeviceName = Environment.MachineName, IPAddress = IPProvider.GetRealIPv4(), Port = _serverPort, Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss" ), ServiceType = "UDP Broadcast Server" , Version = "1.0.0" }; return JsonConvert.SerializeObject(deviceInfo, Formatting.Indented); } private bool IsBroadcastAddress (IPAddress address ) { if (address.Equals(IPAddress.Broadcast)) return true ; var bytes = address.GetAddressBytes(); return bytes[3 ] == 255 ; } public void Stop () { if (!_isRunning) return ; Console.WriteLine(" 正在停止UDP广播服务器..." ); _cancellationTokenSource.Cancel(); } public void Dispose () { Stop(); _cancellationTokenSource?.Dispose(); _udpServer?.Dispose(); } }
📢 UDP 广播客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 public class UdpBroadcastClient : IDisposable { private readonly UdpClient _udpClient; private readonly int _targetPort; private bool _disposed = false ; public UdpBroadcastClient (int targetPort ) { _targetPort = targetPort; _udpClient = new UdpClient(); _udpClient.EnableBroadcast = true ; } public async Task SendBroadcastAsync (string message ) { try { var messageBytes = Encoding.UTF8.GetBytes(message); var broadcastEndPoint = new IPEndPoint(IPAddress.Broadcast, _targetPort); Console.WriteLine($" 发送广播消息: {message} " ); Console.WriteLine($" 目标: {broadcastEndPoint} " ); var sentBytes = await _udpClient.SendAsync(messageBytes, messageBytes.Length, broadcastEndPoint); Console.WriteLine($" 已发送 {sentBytes} 字节" ); await CollectBroadcastResponses(); } catch (Exception ex) { Console.WriteLine($" 发送广播消息失败: {ex.Message} " ); } } private async Task CollectBroadcastResponses () { Console.WriteLine(" 正在收集响应..." ); var responses = new List<(IPEndPoint, string )>(); var timeoutTask = Task.Delay(3000 ); try { while (!timeoutTask.IsCompleted) { var receiveTask = _udpClient.ReceiveAsync(); var completedTask = await Task.WhenAny(receiveTask, timeoutTask); if (completedTask == receiveTask) { var result = await receiveTask; var responseMessage = Encoding.UTF8.GetString(result.Buffer); responses.Add((result.RemoteEndPoint, responseMessage)); Console.WriteLine($" 响应来自 {result.RemoteEndPoint} :" ); Console.WriteLine($" {responseMessage} " ); } else { break ; } } } catch (Exception ex) { Console.WriteLine($" 接收响应时发生错误: {ex.Message} " ); } Console.WriteLine($" 收集完成,共收到 {responses.Count} 个响应" ); } public async Task DiscoverDevicesAsync () { Console.WriteLine(" 开始发现网络设备..." ); var discoveryMessage = new { Type = "Discovery" , From = Environment.MachineName, Timestamp = DateTime.Now, Request = "Who is available?" }; var jsonMessage = JsonConvert.SerializeObject(discoveryMessage); await SendBroadcastAsync(jsonMessage); } public async Task LocalNetworkBroadcastTest () { var networkInfo = GetLocalNetworkInfo(); foreach (var networkInterface in networkInfo) { Console.WriteLine($" 在网络 {networkInterface.Network} 上广播" ); var localBroadcast = new IPEndPoint(networkInterface.BroadcastAddress, _targetPort); var message = $"Hello from {Environment.MachineName} on {networkInterface.Network} " ; var messageBytes = Encoding.UTF8.GetBytes(message); try { await _udpClient.SendAsync(messageBytes, messageBytes.Length, localBroadcast); Console.WriteLine($" 已发送到 已发送到 {localBroadcast} " ); } catch (Exception ex) { Console.WriteLine($" 发送失败: 发送失败: {ex.Message} " ); } } } private List<NetworkInterfaceInfo> GetLocalNetworkInfo () { var networkInterfaces = new List<NetworkInterfaceInfo>(); foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) { if (ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback) { foreach (var ip in ni.GetIPProperties().UnicastAddresses) { if (ip.Address.AddressFamily == AddressFamily.InterNetwork) { var broadcastAddress = CalculateBroadcastAddress(ip.Address, ip.IPv4Mask); networkInterfaces.Add(new NetworkInterfaceInfo { Name = ni.Name, IPAddress = ip.Address, SubnetMask = ip.IPv4Mask, BroadcastAddress = broadcastAddress, Network = $"{ip.Address} /{ip.PrefixLength} " }); } } } } return networkInterfaces; } private IPAddress CalculateBroadcastAddress (IPAddress ipAddress, IPAddress subnetMask ) { var ipBytes = ipAddress.GetAddressBytes(); var maskBytes = subnetMask.GetAddressBytes(); var broadcastBytes = new byte [4 ]; for (int i = 0 ; i < 4 ; i++) { broadcastBytes[i] = (byte )(ipBytes[i] | (~maskBytes[i])); } return new IPAddress(broadcastBytes); } public void Dispose () { if (!_disposed) { _udpClient?.Dispose(); _disposed = true ; } } } public class NetworkInterfaceInfo { public string Name { get ; set ; } public IPAddress IPAddress { get ; set ; } public IPAddress SubnetMask { get ; set ; } public IPAddress BroadcastAddress { get ; set ; } public string Network { get ; set ; } }
高级 UDP 应用场景 游戏状态同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 public class GameServer : IDisposable { private readonly UdpClient _server; private readonly Dictionary<IPEndPoint, PlayerInfo> _players = new (); private readonly Timer _gameUpdateTimer; private readonly object _playersLock = new object (); public GameServer (int port ) { _server = new UdpClient(port); _gameUpdateTimer = new Timer(BroadcastGameState, null , 0 , 16 ); } public async Task StartAsync () { Console.WriteLine(" 游戏服务器启动..." ); while (true ) { try { var result = await _server.ReceiveAsync(); _ = Task.Run(() => ProcessPlayerMessage(result)); } catch (Exception ex) { Console.WriteLine($" 游戏服务器错误: {ex.Message} " ); } } } private async Task ProcessPlayerMessage (UdpReceiveResult result ) { try { var message = Encoding.UTF8.GetString(result.Buffer); var playerData = JsonConvert.DeserializeObject<PlayerMessage>(message); lock (_playersLock) { if (_players.TryGetValue(result.RemoteEndPoint, out var player)) { player.Position = playerData.Position; player.Rotation = playerData.Rotation; player.LastUpdate = DateTime.Now; } else { _players[result.RemoteEndPoint] = new PlayerInfo { Id = Guid.NewGuid().ToString(), Name = playerData.PlayerName ?? $"Player_{_players.Count + 1 } " , Position = playerData.Position, Rotation = playerData.Rotation, EndPoint = result.RemoteEndPoint, LastUpdate = DateTime.Now }; Console.WriteLine($" 新玩家加入: {_players[result.RemoteEndPoint].Name} " ); } } } catch (Exception ex) { Console.WriteLine($" 处理玩家消息错误: {ex.Message} " ); } } private void BroadcastGameState (object state ) { try { List<PlayerInfo> currentPlayers; lock (_playersLock) { var timeout = DateTime.Now.AddSeconds(-5 ); var expiredPlayers = _players.Where(p => p.Value.LastUpdate < timeout).ToList(); foreach (var expired in expiredPlayers) { _players.Remove(expired.Key); Console.WriteLine($" 玩家离线: {expired.Value.Name} " ); } currentPlayers = _players.Values.ToList(); } if (currentPlayers.Count == 0 ) return ; var gameState = new GameState { Timestamp = DateTime.Now, Players = currentPlayers.Select(p => new PlayerState { Id = p.Id, Name = p.Name, Position = p.Position, Rotation = p.Rotation }).ToList() }; var stateJson = JsonConvert.SerializeObject(gameState); var stateBytes = Encoding.UTF8.GetBytes(stateJson); foreach (var player in currentPlayers) { _ = _server.SendAsync(stateBytes, stateBytes.Length, player.EndPoint); } } catch (Exception ex) { Console.WriteLine($" 广播游戏状态错误: {ex.Message} " ); } } public void Dispose () { _gameUpdateTimer?.Dispose(); _server?.Dispose(); } } public class PlayerMessage { public string PlayerName { get ; set ; } public Vector3 Position { get ; set ; } public Vector3 Rotation { get ; set ; } public string Action { get ; set ; } } public class PlayerInfo { public string Id { get ; set ; } public string Name { get ; set ; } public Vector3 Position { get ; set ; } public Vector3 Rotation { get ; set ; } public IPEndPoint EndPoint { get ; set ; } public DateTime LastUpdate { get ; set ; } } public class GameState { public DateTime Timestamp { get ; set ; } public List<PlayerState> Players { get ; set ; } } public class PlayerState { public string Id { get ; set ; } public string Name { get ; set ; } public Vector3 Position { get ; set ; } public Vector3 Rotation { get ; set ; } } public struct Vector3{ public float X { get ; set ; } public float Y { get ; set ; } public float Z { get ; set ; } }
实时数据监控 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 public class DataCollector : IDisposable { private readonly UdpClient _collector; private readonly ConcurrentDictionary<string , SensorData> _latestData = new (); private readonly Timer _reportTimer; private readonly List<DataPoint> _dataHistory = new (); private readonly object _historyLock = new object (); public DataCollector (int port ) { _collector = new UdpClient(port); _reportTimer = new Timer(GenerateReport, null , TimeSpan.Zero, TimeSpan.FromSeconds(10 )); } public async Task StartAsync () { Console.WriteLine(" 数据收集器启动..." ); while (true ) { try { var result = await _collector.ReceiveAsync(); _ = Task.Run(() => ProcessSensorData(result)); } catch (Exception ex) { Console.WriteLine($" 数据收集器错误: {ex.Message} " ); } } } private void ProcessSensorData (UdpReceiveResult result ) { try { var jsonData = Encoding.UTF8.GetString(result.Buffer); var sensorData = JsonConvert.DeserializeObject<SensorData>(jsonData); sensorData.ReceiveTime = DateTime.Now; sensorData.SourceEndPoint = result.RemoteEndPoint.ToString(); _latestData.AddOrUpdate(sensorData.SensorId, sensorData, (key, oldValue) => sensorData); lock (_historyLock) { _dataHistory.Add(new DataPoint { SensorId = sensorData.SensorId, Value = sensorData.Value, Timestamp = sensorData.ReceiveTime, Unit = sensorData.Unit }); if (_dataHistory.Count > 1000 ) { _dataHistory.RemoveAt(0 ); } } ProcessRealtimeData(sensorData); } catch (Exception ex) { Console.WriteLine($" 处理传感器数据错误: {ex.Message} " ); } } private void ProcessRealtimeData (SensorData data ) { if (data.SensorType == "temperature" && data.Value > 50 ) { Console.WriteLine($" 温度异常警告: {data.SensorId} = {data.Value} °C" ); } else if (data.SensorType == "humidity" && (data.Value < 20 || data.Value > 80 )) { Console.WriteLine($" 湿度异常警告: {data.SensorId} = {data.Value} %" ); } Console.WriteLine($"[{data.ReceiveTime:HH:mm:ss.fff} ] {data.SensorId} : {data.Value} {data.Unit} " ); } private void GenerateReport (object state ) { try { Console.WriteLine("\n ========== 数据报告 ==========" ); Console.WriteLine($"报告时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss} " ); Console.WriteLine($"活跃传感器数量: {_latestData.Count} " ); foreach (var sensor in _latestData.Values.OrderBy(s => s.SensorId)) { var timeDiff = DateTime.Now - sensor.ReceiveTime; var status = timeDiff.TotalSeconds < 30 ? "在线" : "离线" ; Console.WriteLine($" {sensor.SensorId} : {sensor.Value} {sensor.Unit} " + $"({status} , {timeDiff.TotalSeconds:F0} 秒前)" ); } lock (_historyLock) { if (_dataHistory.Count > 0 ) { var groupedData = _dataHistory.GroupBy(d => d.SensorId); Console.WriteLine("\n 统计信息:" ); foreach (var group in groupedData) { var values = group .Select(d => d.Value).ToList(); var avg = values.Average(); var min = values.Min(); var max = values.Max(); Console.WriteLine($" {group .Key} : 平均={avg:F2} , 最小={min:F2} , 最大={max:F2} " ); } } } Console.WriteLine("=====================================\n" ); } catch (Exception ex) { Console.WriteLine($" 生成报告错误: {ex.Message} " ); } } public void Dispose () { _reportTimer?.Dispose(); _collector?.Dispose(); } } public class SensorData { public string SensorId { get ; set ; } public string SensorType { get ; set ; } public double Value { get ; set ; } public string Unit { get ; set ; } public DateTime Timestamp { get ; set ; } public DateTime ReceiveTime { get ; set ; } public string SourceEndPoint { get ; set ; } public Dictionary<string , object > Metadata { get ; set ; } = new (); } public class DataPoint { public string SensorId { get ; set ; } public double Value { get ; set ; } public DateTime Timestamp { get ; set ; } public string Unit { get ; set ; } }
综合应用示例 主程序集成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 public static async Task UdpTest (){ const int serverPort = 14756 ; Console.WriteLine(" UDP网络编程演示" ); Console.WriteLine("=" .PadRight(50 , '=' )); while (true ) { Console.WriteLine("\n选择UDP应用模式:" ); Console.WriteLine("1. - 单播服务器" ); Console.WriteLine("2. - 单播客户端" ); Console.WriteLine("3. - 广播服务器" ); Console.WriteLine("4. - 广播客户端" ); Console.WriteLine("5. - 设备发现" ); Console.WriteLine("6. - 游戏服务器" ); Console.WriteLine("7. - 数据收集器" ); Console.WriteLine("8. - 性能测试" ); Console.WriteLine("9. - 退出" ); Console.WriteLine("-" .PadRight(30 , '-' )); Console.Write("请选择: " ); var choice = Console.ReadLine(); switch (choice) { case "1" : await RunUdpServer(serverPort); break ; case "2" : await RunUdpClient("127.0.0.1" , serverPort); break ; case "3" : await RunBroadcastServer(serverPort); break ; case "4" : await RunBroadcastClient(serverPort); break ; case "5" : await RunDeviceDiscovery(serverPort); break ; case "6" : await RunGameServer(serverPort + 1 ); break ; case "7" : await RunDataCollector(serverPort + 2 ); break ; case "8" : await RunPerformanceTest(serverPort); break ; case "9" : return ; default : Console.WriteLine(" 无效选择" ); break ; } } } private static async Task RunUdpServer (int port ){ using var server = new UdpServer(port); await server.StartAsync(); } private static async Task RunUdpClient (string serverIp, int port ){ using var client = new UdpClient(serverIp, port); Console.WriteLine(" UDP客户端模式" ); Console.WriteLine("输入消息发送到服务器 (输入 'quit' 退出):" ); string input; while ((input = Console.ReadLine()) != "quit" ) { if (!string .IsNullOrEmpty(input)) { await client.SendMessageAsync(input); } } } private static async Task RunBroadcastServer (int port ){ using var server = new UdpBroadcastServer(port); await server.StartAsync(); } private static async Task RunBroadcastClient (int port ){ using var client = new UdpBroadcastClient(port); Console.WriteLine(" 广播客户端模式" ); Console.WriteLine("1. 发送简单广播" ); Console.WriteLine("2. 设备发现" ); Console.WriteLine("3. 本地网络广播" ); Console.Write("选择: " ); var choice = Console.ReadLine(); switch (choice) { case "1" : await client.SendBroadcastAsync("Hello, this is a broadcast message!" ); break ; case "2" : await client.DiscoverDevicesAsync(); break ; case "3" : await client.LocalNetworkBroadcastTest(); break ; } } private static async Task RunPerformanceTest (int port ){ Console.WriteLine(" UDP性能测试" ); using var server = new UdpServer(port); _ = Task.Run(() => server.StartAsync()); await Task.Delay(1000 ); using var client = new UdpClient("127.0.0.1" , port); Console.WriteLine("开始性能测试..." ); var stopwatch = Stopwatch.StartNew(); await client.SendBatchMessagesAsync(1000 ); stopwatch.Stop(); Console.WriteLine($" 性能测试完成,总耗时: {stopwatch.ElapsedMilliseconds} ms" ); Console.WriteLine($" 平均每条消息: {stopwatch.ElapsedMilliseconds / 1000.0 :F2} ms" ); }
性能优化与经验分享 性能优化技巧 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public class OptimizedUdpServer { private readonly Socket _socket; private readonly byte [] _buffer = new byte [8192 ]; private readonly ArrayPool<byte > _arrayPool = ArrayPool<byte >.Shared; public OptimizedUdpServer (int port ) { _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); _socket.Bind(new IPEndPoint(IPAddress.Any, port)); _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 1024 * 1024 ); _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, 1024 * 1024 ); } public async Task StartHighPerformanceAsync () { while (true ) { try { var result = await ReceiveFromAsync(); _ = ProcessMessageFast(result.buffer, result.length, result.remoteEndPoint); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message} " ); } } } private async ValueTask<(byte [] buffer, int length, EndPoint remoteEndPoint)> ReceiveFromAsync() { var buffer = _arrayPool.Rent(8192 ); var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0 ); try { var result = await _socket.ReceiveFromAsync(buffer, SocketFlags.None, remoteEndPoint); return (buffer, result.ReceivedBytes, result.RemoteEndPoint); } catch { _arrayPool.Return(buffer); throw ; } } private Task ProcessMessageFast (byte [] buffer, int length, EndPoint remoteEndPoint ) { try { var message = Encoding.UTF8.GetString(buffer, 0 , length); return Task.CompletedTask; } finally { _arrayPool.Return(buffer); } } }
错误处理与重试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 public class ReliableUdpClient { private readonly UdpClient _client; private readonly Dictionary<uint , PendingMessage> _pendingMessages = new (); private uint _messageId = 0 ; public async Task<bool > SendReliableAsync (string message, int maxRetries = 3 ) { var id = ++_messageId; var reliableMessage = new ReliableMessage { Id = id, Content = message, Timestamp = DateTime.Now }; for (int attempt = 1 ; attempt <= maxRetries; attempt++) { try { await SendMessageWithId(reliableMessage); var ackReceived = await WaitForAck(id, TimeSpan.FromSeconds(2 )); if (ackReceived) { return true ; } Console.WriteLine($"重试 {attempt} /{maxRetries} ..." ); } catch (Exception ex) { Console.WriteLine($"发送失败 (尝试 {attempt} ): {ex.Message} " ); } if (attempt < maxRetries) { await Task.Delay(TimeSpan.FromMilliseconds(Math.Pow(2 , attempt) * 100 )); } } return false ; } private async Task<bool > WaitForAck (uint messageId, TimeSpan timeout ) { var timeoutTask = Task.Delay(timeout); while (!timeoutTask.IsCompleted) { if (!_pendingMessages.ContainsKey(messageId)) { return true ; } await Task.Delay(50 ); } return false ; } } public class ReliableMessage { public uint Id { get ; set ; } public string Content { get ; set ; } public DateTime Timestamp { get ; set ; } } public class PendingMessage { public ReliableMessage Message { get ; set ; } public DateTime SendTime { get ; set ; } public int RetryCount { get ; set ; } }
小结 UDP 网络编程在 C#中提供了高效的实时通信能力,适用于多种应用场景:
技术要点总结
高性能 - 低延迟、高吞吐量的数据传输
灵活性 - 支持单播、广播、组播等多种通信模式
实时性 - 适合游戏、监控、流媒体等实时应用
网络发现 - 便于实现服务发现和设备通信
数据收集 - 高效的传感器数据采集和分发
开发经验分享
合理设置缓冲区大小 - 根据数据量调整接收/发送缓冲区
实现可靠性机制 - 在应用层添加确认、重传、去重机制
控制发送频率 - 避免网络拥塞和丢包
错误处理 - 妥善处理网络异常和超时情况
性能监控 - 监控延迟、丢包率等关键指标
通过合理使用 UDP 协议,我们可以构建出高效、实时的网络应用程序,满足现代应用对快速数据传输的需求。
选择建议 :
实时性要求高 : 选择 UDP(游戏、流媒体)
可靠性要求高 : 选择 TCP(文件传输、Web)
广播需求 : UDP 天然支持广播和组播
简单实现 : UDP 协议简单,开发效率高
相关资源 :