C# WinForm中UdpClient连续接收UDP数据及字符串处理求助
问题根因
原代码仅单次调用UdpClient.Receive()阻塞方法,读取到1个UDP数据包后就结束执行,没有实现持续监听逻辑;且监听逻辑直接运行在UI主线程,长时间运行会直接导致界面无响应。
实现步骤
- 将
UdpClient声明为窗体内的全局变量,方便启动/停止时统一管理资源,避免泄漏 - 点击启动按钮后,在后台线程执行循环监听逻辑,杜绝阻塞UI线程
- 循环内持续调用
Receive()方法读取6009端口的数据包,直到手动触发停止 - 对读取到的字符串做格式修正:将单独的回车符(CR,
\r)替换为标准回车换行(CRLF,\r\n),同时做兼容处理避免重复替换已符合规范的CRLF内容 - 跨线程更新UI内容时使用控件的
Invoke方法做线程安全调用,避免WinForm跨线程访问异常 - 格式修正完成的字符串可直接通过UDP发送给对接的目标软件
完整修改代码
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { // 全局UDP客户端、监听线程、运行控制标记 private UdpClient _udpClient; private Thread _listenThread; private bool _isListening = false; // 请修改为实际对接软件的监听IP和端口 private readonly IPEndPoint _forwardTarget = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7001); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // 初始化UDP客户端监听6009端口 _udpClient = new UdpClient(6009); _isListening = true; // 启动后台线程跑监听逻辑 _listenThread = new Thread(ReceiveLoop) { IsBackground = true }; _listenThread.Start(); // 更新控件状态 button1.Enabled = false; textBox1.Enabled = false; textBox3.Enabled = false; button3.Enabled = true; } private void ReceiveLoop() { IPEndPoint remoteEp = new IPEndPoint(IPAddress.Any, 0); try { while (_isListening) { // 阻塞等待接收UDP数据包 byte[] receiveBytes = _udpClient.Receive(ref remoteEp); string rawData = Encoding.ASCII.GetString(receiveBytes); // 字符串格式化:CR后插入LF,避免重复替换已有的CRLF string formattedData = rawData.Replace("\r\n", "\0").Replace("\r", "\r\n").Replace("\0", "\r\n"); // 转发格式化后的数据到对接软件 byte[] forwardBytes = Encoding.ASCII.GetBytes(formattedData); _udpClient.Send(forwardBytes, forwardBytes.Length, _forwardTarget); // 线程安全更新界面显示 UpdateUIDisplay(formattedData); } } catch (SocketException) { // 主动关闭客户端触发的异常无需处理 } finally { _udpClient?.Close(); } } private void UpdateUIDisplay(string content) { if (label2.InvokeRequired) { Invoke(new Action<string>(UpdateUIDisplay), content); return; } label2.Text = content; } private void button3_Click(object sender, EventArgs e) { // 停止监听逻辑 _isListening = false; _udpClient?.Close(); _listenThread?.Join(1000); // 恢复控件状态 button1.Enabled = true; textBox1.Enabled = true; textBox3.Enabled = true; button3.Enabled = false; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // 窗口关闭时主动释放资源,避免后台进程残留 _isListening = false; _udpClient?.Close(); } private void label2_Click(object sender, EventArgs e) { } private void Form1_Load(object sender, EventArgs e) { button3.Enabled = false; } private void button2_Click(object sender, EventArgs e) { } } }
注意事项
- 代码中
_forwardTarget参数需要替换为实际对接软件的监听地址和端口 - 若接收的NMEA定位数据存在分包、粘包情况,可自行添加内存缓冲区,拼接完完整语句后再做格式化和转发
- 监听线程设置为后台线程,避免窗口关闭后程序进程仍在后台驻留
- 停止监听时主动关闭UdpClient,可立刻中断阻塞的
Receive()方法,快速退出监听循环
内容的提问来源于stack exchange,提问作者Marcelogeo
相关产品推荐
相关产品推荐

