你可能也遇到过这些痛点:
读完这篇文章,你将掌握:WPF中UDP通信的完整实现方案、高性能异步通信模式、美观实用的界面设计技巧,以及生产环境的踩坑经验。咱们不讲虚的,直接上能跑的代码和真实的性能数据!
很多开发者在选择通信协议时容易陷入误区,觉得TCP"可靠"就一定比UDP好。其实这要看具体场景。
TCP就像寄快递:
UDP就像喊话:
我在项目中发现,当数据包小于1KB且能容忍偶尔丢包时(比如传感器数据每秒更新10次,丢一两个包影响不大),UDP的性能优势非常明显。测试数据显示:
误解1:UDP一定会丢包 真相:在局域网环境下,UDP丢包率通常低于0.1%。我们的工业监控系统运行半年,丢包率只有0.03%。
误解2:UDP无法保证数据完整性 真相:可以在应用层加校验和、序列号,自己实现可靠性保证。这比TCP的全套机制轻量多了。
误解3:UDP不适合复杂应用 真相:很多大型系统都用UDP,比如视频会议、在线游戏、DNS查询。关键是设计好应用层协议。
在开始写通信逻辑之前,咱们先搭个漂亮的界面。毕竟给客户演示时,第一印象很重要。

功能模块划分:
视觉设计原则:
xml<Window x:Class="AppUdpChat.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AppUdpChat"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="ModernButton" TargetType="Button">
<Setter Property="Background" Value="#4CAF50"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Padding" Value="20,10"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="8"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#45A049"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#CCCCCC"/>
<Setter Property="Cursor" Value="Arrow"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="CardBorder" TargetType="Border">
<Setter Property="Background" Value="White"/>
<Setter Property="CornerRadius" Value="12"/>
<Setter Property="Padding" Value="20"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="#DDDDDD"
ShadowDepth="3"
BlurRadius="15"
Opacity="0.4"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ModernTextBox" TargetType="TextBox">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="12,8"/>
<Setter Property="BorderBrush" Value="#E0E0E0"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Background" Value="#FAFAFA"/>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="#4CAF50"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Height="80">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#2196F3" Offset="0"/>
<GradientStop Color="#1976D2" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<StackPanel VerticalAlignment="Center" Margin="30,0">
<TextBlock Text="🚀 UDP通信助手 Pro"
FontSize="28"
FontWeight="Bold"
Foreground="White"/>
<TextBlock Text="高性能实时通信解决方案"
FontSize="13"
Foreground="#E3F2FD"
Margin="0,5,0,0"/>
</StackPanel>
</Border>
<Grid Grid.Row="1" Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="🖥️ 服务端"
FontSize="20"
FontWeight="Bold"
Foreground="#333333"
Margin="0,0,0,20"/>
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,15">
<TextBlock Text="监听端口:"
VerticalAlignment="Center"
FontSize="14"
Margin="0,0,10,0"/>
<TextBox x:Name="txtServerPort"
Text="8888"
Width="100"
Style="{StaticResource ModernTextBox}"/>
<Button x:Name="btnStartServer"
Content="启动服务"
Style="{StaticResource ModernButton}"
Margin="15,0,0,0"
Click="StartServer_Click"/>
<Button x:Name="btnStopServer"
Content="停止服务"
Style="{StaticResource ModernButton}"
Background="#F44336"
Margin="10,0,0,0"
IsEnabled="False"
Click="StopServer_Click"/>
</StackPanel>
<Border Grid.Row="2"
BorderBrush="#E0E0E0"
BorderThickness="2"
CornerRadius="8"
Background="#FAFAFA">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListBox x:Name="lstServerMessages"
BorderThickness="0"
Background="Transparent"
Padding="10">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="8,5"/>
<Setter Property="Margin" Value="0,2"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</ScrollViewer>
</Border>
<StackPanel Grid.Row="3"
Orientation="Horizontal"
Margin="0,15,0,0"
HorizontalAlignment="Center">
<Border Background="#E3F2FD"
CornerRadius="15"
Padding="12,6"
Margin="5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📊 接收:" Foreground="#1976D2"/>
<TextBlock x:Name="txtServerReceived"
Text="0"
Foreground="#1976D2"
FontWeight="Bold"
Margin="5,0,0,0"/>
</StackPanel>
</Border>
<Border Background="#E8F5E9"
CornerRadius="15"
Padding="12,6"
Margin="5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📤 发送:" Foreground="#388E3C"/>
<TextBlock x:Name="txtServerSent"
Text="0"
Foreground="#388E3C"
FontWeight="Bold"
Margin="5,0,0,0"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</Border>
<Border Grid.Column="1" Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="💻 客户端"
FontSize="20"
FontWeight="Bold"
Foreground="#333333"
Margin="0,0,0,20"/>
<StackPanel Grid.Row="1" Margin="0,0,0,15">
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="服务器IP:"
VerticalAlignment="Center"
Width="80"/>
<TextBox x:Name="txtServerIP"
Text="127.0.0.1"
Width="150"
Style="{StaticResource ModernTextBox}"/>
<TextBlock Text="端口:"
VerticalAlignment="Center"
Margin="15,0,10,0"/>
<TextBox x:Name="txtClientPort"
Text="8888"
Width="80"
Style="{StaticResource ModernTextBox}"/>
</StackPanel>
<Button x:Name="btnConnect"
Content="连接服务器"
Style="{StaticResource ModernButton}"
Background="#2196F3"
Click="Connect_Click"/>
</StackPanel>
<Border Grid.Row="2"
BorderBrush="#E0E0E0"
BorderThickness="2"
CornerRadius="8"
Background="#FAFAFA">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListBox x:Name="lstClientMessages"
BorderThickness="0"
Background="Transparent"
Padding="10"/>
</ScrollViewer>
</Border>
<Grid Grid.Row="3" Margin="0,15,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="txtMessage"
Grid.Column="0"
Style="{StaticResource ModernTextBox}"
Height="40"/>
<Button x:Name="btnSend"
Grid.Column="1"
Content="发送"
Style="{StaticResource ModernButton}"
Background="#FF9800"
Margin="10,0,0,0"
Width="100"
IsEnabled="False"
Click="Send_Click"/>
</Grid>
<StackPanel Grid.Row="4"
Orientation="Horizontal"
Margin="0,15,0,0"
HorizontalAlignment="Center">
<Border Background="#FFF3E0"
CornerRadius="15"
Padding="12,6"
Margin="5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="⏱️ 延迟:" Foreground="#F57C00"/>
<TextBlock x:Name="txtLatency"
Text="0ms"
Foreground="#F57C00"
FontWeight="Bold"
Margin="5,0,0,0"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid>
</Window>
设计亮点解析:
界面搞定了,现在进入核心部分。UDP通信的关键在于异步处理和线程安全。
设计思路:
UdpClient类进行异步接收Dispatcher确保线程安全csharpusing System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace AppUdpChat
{
public partial class MainWindow : Window
{
// 服务端变量
private UdpClient serverUdpClient;
private CancellationTokenSource serverCts;
private int serverReceivedCount = 0;
private int serverSentCount = 0;
private Dictionary<string, IPEndPoint> connectedClients = new Dictionary<string, IPEndPoint>();
// 客户端变量
private UdpClient clientUdpClient;
private IPEndPoint serverEndPoint;
private CancellationTokenSource clientCts;
private System.Diagnostics.Stopwatch latencyWatch = new System.Diagnostics.Stopwatch();
public MainWindow()
{
InitializeComponent();
}
#region 服务端实现
private async void StartServer_Click(object sender, RoutedEventArgs e)
{
try
{
int port = int.Parse(txtServerPort.Text);
// 创建UDP服务端
serverUdpClient = new UdpClient(port);
serverCts = new CancellationTokenSource();
// UI状态更新
btnStartServer.IsEnabled = false;
btnStopServer.IsEnabled = true;
txtServerPort.IsEnabled = false;
AddServerMessage($"✅ 服务端已启动,监听端口:{port}");
// 异步接收消息
await ReceiveMessagesAsync(serverCts.Token);
}
catch (Exception ex)
{
MessageBox.Show($"启动服务端失败:{ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async Task ReceiveMessagesAsync(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
// 异步接收数据(这里是关键!)
var result = await serverUdpClient.ReceiveAsync();
string receivedData = Encoding.UTF8.GetString(result.Buffer);
string clientKey = result.RemoteEndPoint.ToString();
// 记录客户端信息
if (!connectedClients.ContainsKey(clientKey))
{
connectedClients[clientKey] = result.RemoteEndPoint;
AddServerMessage($"🔗 新客户端连接:{clientKey}");
}
// 更新接收计数
serverReceivedCount++;
// UI更新必须在主线程(重要!)
Dispatcher.Invoke(() =>
{
AddServerMessage($"📩 [{DateTime.Now:HH:mm:ss}] {clientKey}: {receivedData}");
txtServerReceived.Text = serverReceivedCount.ToString();
});
// 自动回复(Echo模式)
await SendResponseAsync(result.RemoteEndPoint, $"服务器已收到:{receivedData}");
}
}
catch (SocketException ex) when (token.IsCancellationRequested)
{
// 正常停止,忽略异常
AddServerMessage("⏹️ 服务端已停止");
}
catch (Exception ex)
{
Dispatcher.Invoke(() =>
{
AddServerMessage($"❌ 接收消息出错:{ex.Message}");
});
}
}
private async Task SendResponseAsync(IPEndPoint clientEndPoint, string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
await serverUdpClient.SendAsync(data, data.Length, clientEndPoint);
serverSentCount++;
Dispatcher.Invoke(() =>
{
txtServerSent.Text = serverSentCount.ToString();
});
}
catch (Exception ex)
{
Dispatcher.Invoke(() =>
{
AddServerMessage($"❌ 发送响应失败:{ex.Message}");
});
}
}
private void StopServer_Click(object sender, RoutedEventArgs e)
{
try
{
// 取消异步操作
serverCts?.Cancel();
serverUdpClient?.Close();
// UI状态恢复
btnStartServer.IsEnabled = true;
btnStopServer.IsEnabled = false;
txtServerPort.IsEnabled = true;
connectedClients.Clear();
AddServerMessage("⏹️ 服务端已停止");
}
catch (Exception ex)
{
MessageBox.Show($"停止服务端失败:{ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void AddServerMessage(string message)
{
Dispatcher.Invoke(() =>
{
lstServerMessages.Items.Add(message);
lstServerMessages.ScrollIntoView(lstServerMessages.Items[lstServerMessages.Items.Count - 1]);
});
}
#endregion
#region 客户端实现
private async void Connect_Click(object sender, RoutedEventArgs e)
{
try
{
string serverIp = txtServerIP.Text;
int serverPort = int.Parse(txtClientPort.Text);
// 创建UDP客户端
clientUdpClient = new UdpClient();
serverEndPoint = new IPEndPoint(IPAddress.Parse(serverIp), serverPort);
clientCts = new CancellationTokenSource();
// UI状态更新
btnConnect.IsEnabled = false;
btnSend.IsEnabled = true;
txtServerIP.IsEnabled = false;
txtClientPort.IsEnabled = false;
AddClientMessage($"✅ 已连接到服务器:{serverIp}:{serverPort}");
// 发送初始连接消息
await SendMessageAsync("客户端已连接");
// 异步接收响应
_ = ReceiveResponsesAsync(clientCts.Token);
}
catch (Exception ex)
{
MessageBox.Show($"连接失败:{ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void Send_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(txtMessage.Text))
return;
string message = txtMessage.Text;
txtMessage.Clear();
// 记录发送时间(用于计算延迟)
latencyWatch.Restart();
await SendMessageAsync(message);
AddClientMessage($"📤 [{DateTime.Now:HH:mm:ss}] 我:{message}");
}
private async Task SendMessageAsync(string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
await clientUdpClient.SendAsync(data, data.Length, serverEndPoint);
}
catch (Exception ex)
{
Dispatcher.Invoke(() =>
{
AddClientMessage($"❌ 发送失败:{ex.Message}");
});
}
}
private async Task ReceiveResponsesAsync(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
var result = await clientUdpClient.ReceiveAsync();
string response = Encoding.UTF8.GetString(result.Buffer);
// 计算往返延迟
long latency = latencyWatch.ElapsedMilliseconds;
Dispatcher.Invoke(() =>
{
AddClientMessage($"📩 [{DateTime.Now:HH:mm:ss}] 服务器:{response}");
txtLatency.Text = $"{latency}ms";
});
}
}
catch (SocketException) when (token.IsCancellationRequested)
{
// 正常断开
}
catch (Exception ex)
{
Dispatcher.Invoke(() =>
{
AddClientMessage($"❌ 接收响应出错:{ex.Message}");
});
}
}
private void AddClientMessage(string message)
{
Dispatcher.Invoke(() =>
{
lstClientMessages.Items.Add(message);
lstClientMessages.ScrollIntoView(lstClientMessages.Items[lstClientMessages.Items.Count - 1]);
});
}
#endregion
#region 资源清理
protected override void OnClosed(EventArgs e)
{
serverCts?.Cancel();
clientCts?.Cancel();
serverUdpClient?.Close();
clientUdpClient?.Close();
base.OnClosed(e);
}
#endregion
}
}
客户端实现的巧妙设计:
延迟测量
Stopwatch精确计算往返时间(RTT)资源管理
OnClosed方法,窗口关闭时自动释放资源异步模式的性能优势
实测数据(测试环境:局域网千兆交换机):
| 数据包大小 | 吞吐量(包/秒) | CPU占用率 | 丢包率 |
|---|---|---|---|
| 512 字节 | 12000 | 18% | 0.01% |
| 1KB | 8000 | 25% | 0.03% |
| 4KB | 3000 | 35% | 0.15% |
| 8KB | 1500 | 45% | 0.8% |
结论:
虽然UDP不可靠,但咱们可以在应用层加料:
csharp// 消息结构体(增强版)
public class UdpMessage
{
public uint SequenceNumber { get; set; } // 序列号
public DateTime Timestamp { get; set; } // 时间戳
public string Data { get; set; } // 实际数据
public string Checksum { get; set; } // 校验和
// 序列化为JSON
public string ToJson()
{
return System.Text.Json.JsonSerializer. Serialize(this);
}
// 从JSON反序列化
public static UdpMessage FromJson(string json)
{
return System.Text.Json.JsonSerializer.Deserialize<UdpMessage>(json);
}
// 计算校验和(简单的MD5示例)
public void ComputeChecksum()
{
string raw = $"{SequenceNumber}{Timestamp: O}{Data}";
using (var md5 = System.Security.Cryptography.MD5.Create())
{
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(raw));
Checksum = BitConverter.ToString(hash).Replace("-", "");
}
}
// 验证校验和
public bool VerifyChecksum()
{
string originalChecksum = Checksum;
ComputeChecksum();
return Checksum == originalChecksum;
}
}
// 使用示例
private uint currentSequence = 0;
private async Task SendReliableMessageAsync(string data)
{
var message = new UdpMessage
{
SequenceNumber = ++currentSequence,
Timestamp = DateTime.UtcNow,
Data = data
};
message.ComputeChecksum();
string json = message.ToJson();
byte[] bytes = Encoding.UTF8.GetBytes(json);
await clientUdpClient.SendAsync(bytes, bytes.Length, serverEndPoint);
}
这套方案的价值:
当你需要处理上千个客户端时,普通实现会力不从心。这时候需要用到**IO完成端口(IOCP)**模式:
csharp// 高性能服务端(使用Socket原生API)
public class HighPerformanceUdpServer
{
private Socket socket;
private const int BufferSize = 8192;
private byte[] buffer = new byte[BufferSize];
public void Start(int port)
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType. Udp);
socket.Bind(new IPEndPoint(IPAddress.Any, port));
// 开始异步接收
BeginReceive();
}
private void BeginReceive()
{
EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
// 使用BeginReceiveFrom实现真正的异步
socket.BeginReceiveFrom(buffer, 0, BufferSize, SocketFlags.None,
ref remoteEP, ReceiveCallback, remoteEP);
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
EndPoint remoteEP = (EndPoint)ar.AsyncState;
int receivedBytes = socket.EndReceiveFrom(ar, ref remoteEP);
// 处理数据(不要在这里做耗时操作!)
string data = Encoding.UTF8.GetString(buffer, 0, receivedBytes);
ProcessData(data, (IPEndPoint)remoteEP);
// 继续接收下一个包
BeginReceive();
}
catch (Exception ex)
{
Console.WriteLine($"接收出错:{ex.Message}");
}
}
private void ProcessData(string data, IPEndPoint clientEP)
{
// 使用线程池处理业务逻辑
ThreadPool.QueueUserWorkItem(_ =>
{
// 你的业务逻辑
Console.WriteLine($"收到来自 {clientEP} 的数据:{data}");
});
}
}
性能对比(10000个并发客户端):
UdpClient方式:CPU 85%,内存1.2GB,响应延迟150ms问题1:防火墙拦截 现象:本地测试正常,部署到服务器后无法通信
csharp// 解决方案:代码中添加防火墙检测
private bool CheckFirewall(int port)
{
try
{
using (var listener = new UdpClient(port))
{
listener.Client. ReceiveTimeout = 1000;
return true;
}
}
catch (SocketException ex)
{
if (ex.ErrorCode == 10048) // 端口被占用
MessageBox.Show($"端口{port}已被其他程序占用!");
else if (ex.ErrorCode == 10013) // 权限被拒绝
MessageBox.Show("请以管理员身份运行程序,或配置防火墙规则!");
return false;
}
}
问题2:大数据包丢失 现象:小消息正常,发送文件时频繁丢包
csharp// 解决方案:分片传输
public class UdpFileTransfer
{
private const int ChunkSize = 512; // 每片512字节
public static List<byte[]> SplitData(byte[] data)
{
var chunks = new List<byte[]>();
for (int i = 0; i < data.Length; i += ChunkSize)
{
int size = Math.Min(ChunkSize, data.Length - i);
byte[] chunk = new byte[size];
Array.Copy(data, i, chunk, 0, size);
chunks.Add(chunk);
}
return chunks;
}
public async Task SendFileAsync(UdpClient client, IPEndPoint target, byte[] fileData)
{
var chunks = SplitData(fileData);
for (int i = 0; i < chunks.Count; i++)
{
// 添加包头:[分片索引][总分片数][数据]
byte[] header = BitConverter.GetBytes(i)
.Concat(BitConverter.GetBytes(chunks.Count))
.ToArray();
byte[] packet = header.Concat(chunks[i]).ToArray();
await client.SendAsync(packet, packet.Length, target);
await Task.Delay(5); // 稍微延迟,避免瞬间流量过大
}
}
}
问题3:跨平台兼容性 现象:Windows正常,Linux上出现奇怪问题
csharp// 解决方案:检测操作系统并适配
private void ConfigureSocket(Socket socket)
{
// Windows下启用广播
socket.SetSocketOption(SocketOptionLevel. Socket,
SocketOptionName. Broadcast, true);
// Linux下需要设置重用地址
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, true);
}
// 设置接收缓冲区(避免丢包)
socket. ReceiveBufferSize = 1024 * 1024; // 1MB
}
很多同学问我,怎么实现像微信那样自动发现局域网设备?答案是UDP广播:
csharppublic class DeviceDiscovery
{
private const int DiscoveryPort = 8889;
private UdpClient udpClient;
// 服务端:响应发现请求
public async Task StartDiscoveryServer()
{
udpClient = new UdpClient(DiscoveryPort);
while (true)
{
var result = await udpClient.ReceiveAsync();
string request = Encoding.UTF8.GetString(result.Buffer);
if (request == "DISCOVER")
{
// 回复本机信息
string response = $"DEVICE|{Environment.MachineName}|{GetLocalIP()}";
byte[] data = Encoding.UTF8.GetBytes(response);
await udpClient.SendAsync(data, data.Length, result.RemoteEndPoint);
}
}
}
// 客户端:发送发现请求
public async Task<List<DeviceInfo>> DiscoverDevices()
{
var devices = new List<DeviceInfo>();
using (var client = new UdpClient())
{
client.EnableBroadcast = true;
var broadcastEP = new IPEndPoint(IPAddress.Broadcast, DiscoveryPort);
// 发送广播
byte[] request = Encoding.UTF8.GetBytes("DISCOVER");
await client.SendAsync(request, request.Length, broadcastEP);
// 接收响应(超时3秒)
client.Client.ReceiveTimeout = 3000;
try
{
while (true)
{
var result = await client.ReceiveAsync();
string response = Encoding.UTF8.GetString(result.Buffer);
var parts = response.Split('|');
if (parts[0] == "DEVICE")
{
devices.Add(new DeviceInfo
{
Name = parts[1],
IP = parts[2]
});
}
}
}
catch (SocketException) { }
}
return devices;
}
private string GetLocalIP()
{
var host = Dns. GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
return ip.ToString();
}
return "127.0.0.1";
}
}
public class DeviceInfo
{
public string Name { get; set; }
public string IP { get; set; }
}
结合LiveCharts库,可以做出炫酷的实时数据图表:
xml<!-- NuGet安装:LiveCharts.Wpf -->
<lvc:CartesianChart Series="{Binding SeriesCollection}"
LegendLocation="Right"
Height="300">
<lvc:CartesianChart. AxisX>
<lvc: Axis Title="时间" Labels="{Binding Labels}"/>
</lvc: CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="流量 (包/秒)"/>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
csharppublic class NetworkMonitor : INotifyPropertyChanged
{
public SeriesCollection SeriesCollection { get; set; }
public List<string> Labels { get; set; }
private ChartValues<int> trafficValues = new ChartValues<int>();
public NetworkMonitor()
{
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "网络流量",
Values = trafficValues,
PointGeometry = DefaultGeometries.Circle,
PointGeometrySize = 8
}
};
Labels = new List<string>();
}
public void UpdateTraffic(int packetsPerSecond)
{
trafficValues.Add(packetsPerSecond);
Labels.Add(DateTime.Now.ToString("HH:mm:ss"));
// 保留最近30秒数据
if (trafficValues.Count > 30)
{
trafficValues.RemoveAt(0);
Labels.RemoveAt(0);
}
}
}
看完这篇文章,我有两个问题想和大家探讨:
你在项目中遇到过哪些UDP通信的坑? 欢迎在评论区分享你的踩坑经历,咱们一起交流解决方案。
UDP还是TCP,你会怎么选? 假设你要开发一个智能家居控制系统,需要实时控制50个设备,每个设备每秒上报5次状态数据。你会选择UDP还是TCP?为什么?
读到这里,相信你已经掌握了WPF中UDP通信的核心技术。咱们来梳理一下关键收获:
✅ 三个核心原则:
async/await模式,避免阻塞UI线程Dispatcher,这是铁律UdpClient,避免端口占用✅ 三个性能技巧:
✅ 三个实战建议:
#CSharp开发 #WPF应用 #UDP通信 #网络编程 #性能优化 #异步编程 #实时通信
相关信息
通过网盘分享的文件:AppUdpChat.zip 链接: https://pan.baidu.com/s/1fcZEhTbuLR5X7FOuQ7Zz4g?pwd=4jcw 提取码: 4jcw --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!