【C# 上位机UDP通讯】

发布于:2025-03-20 ⋅ 阅读:(22) ⋅ 点赞:(0)

1. 概述

UDP(用户数据报协议)是一种无连接的传输层协议,具有传输效率高、实时性强的特点,广泛应用于物联网、实时监控、网络广播等场景。本文将详细介绍如何使用 C# 开发一个 UDP 通信上位机软件,实现消息的发送与接收,并实时显示带有时间戳的通信日志。

在这里插入图片描述

源码地址:https://download.csdn.net/download/VOR234/90494929

2. 开发环境

  • 开发工具:Visual Studio 2022(.NET Framework 4.7.2+)
  • 核心类库System.Net.Sockets.UdpClient
  • 网络调试工具推荐

3. 功能需求

  1. UDP监听:创建后台线程持续监听指定端口。
  2. 消息发送:支持向指定IP和端口发送文本消息。
  3. 实时显示
    • 接收消息时自动显示来源IP和端口。
    • 发送消息时记录目标地址。
  4. 日志记录:所有收发操作均附带毫秒级时间戳。
  5. 线程安全:跨线程更新UI控件。

4. 实现步骤

4.1 界面设计

在这里插入图片描述

核心控件说明:

  • 接收日志框:TextBox(Multiline + ScrollBars)
  • 目标IP输入:TextBox(默认127.0.0.1)
  • 目标端口输入:TextBox(默认10023)
  • 消息输入框:TextBox
  • 发送按钮:Button
    完整代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace UDP_app
{
    public partial class Form1 : Form
    {
        private UdpClient _udpListener;
        private Thread _listenThread;
        private const int ListenPort = 10023; // 监听端口号

        public Form1()
        {
            InitializeComponent();
            InitializeUdpListener();
        }

        private void InitializeUdpListener()
        {
            _udpListener = new UdpClient(ListenPort);
            _listenThread = new Thread(ReceiveMessages);
            _listenThread.IsBackground = true;
            _listenThread.Start();
        }

        private void ReceiveMessages()
        {
            while (true)
            {
                IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, ListenPort);
                byte[] receivedBytes = _udpListener.Receive(ref remoteEndPoint);
                string receivedMessage = Encoding.UTF8.GetString(receivedBytes);
                AppendTextToOutput($"Received: {receivedMessage} to {remoteEndPoint.Address}:{remoteEndPoint.Port}");
            }
        }

        private void AppendTextToOutput(string text)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<string>(AppendTextToOutput), text);
            }
            else
            {
                // 添加时间戳
                string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                text = $"{timestamp} {text}";
                txtOutput.AppendText(text + Environment.NewLine);
                //显示最后一行
                txtOutput.SelectionStart = txtOutput.Text.Length;
                txtOutput.ScrollToCaret();
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            string targetIp = txtTargetIp.Text;
            int targetPort = int.Parse(txtTargetPort.Text);
            string message = txtMessage.Text;

            using (UdpClient udpClient = new UdpClient())
            {
                var sendBytes = Encoding.UTF8.GetBytes(message);
                udpClient.Send(sendBytes, sendBytes.Length, targetIp, targetPort);
                AppendTextToOutput($"Sent: {message} to {targetIp}:{targetPort}");
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            _udpListener.Close();
        }
    }
}

4.2 UDP监听实现

通过后台线程持续监听UDP端口:

private UdpClient _udpListener;
private Thread _listenThread;
private const int ListenPort = 10023;

private void InitializeUdpListener()
{
    _udpListener = new UdpClient(ListenPort);
    _listenThread = new Thread(ReceiveMessages);
    _listenThread.IsBackground = true; // 设置为后台线程
    _listenThread.Start();
}

private void ReceiveMessages()
{
    while (true)
    {
        IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, ListenPort);
        byte[] receivedBytes = _udpListener.Receive(ref remoteEndPoint);
        string receivedMessage = Encoding.UTF8.GetString(receivedBytes);
        AppendTextToOutput($"Received: {receivedMessage} from {remoteEndPoint}");
    }
}

4.3 消息发送功能

使用独立的UdpClient实例发送数据:

private void btnSend_Click(object sender, EventArgs e)
{
    string targetIp = txtTargetIp.Text;
    int targetPort = int.Parse(txtTargetPort.Text);
    string message = txtMessage.Text;

    using (UdpClient udpClient = new UdpClient())
    {
        byte[] sendBytes = Encoding.UTF8.GetBytes(message);
        udpClient.Send(sendBytes, sendBytes.Length, targetIp, targetPort);
        AppendTextToOutput($"Sent: {message} to {targetIp}:{targetPort}");
    }
}

4.4 线程安全日志显示

使用Invoke跨线程更新UI:

private void AppendTextToOutput(string text)
{
    if (InvokeRequired)
    {
        Invoke(new Action<string>(AppendTextToOutput), text);
    }
    else
    {
        string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
        txtOutput.AppendText($"[{timestamp}] {text}\r\n");
        txtOutput.ScrollToCaret(); // 自动滚动到底部
    }
}

4.5 资源释放处理

窗口关闭时释放UDP资源:

protected override void OnFormClosing(FormClosingEventArgs e)
{
    base.OnFormClosing(e);
    _udpListener?.Close(); // 释放监听器
    _listenThread?.Join(500); // 等待线程退出
}

5. 使用效果演示

  1. 启动监听:运行程序后自动开始监听10023端口
  2. 发送测试
    • 目标地址填写本机IP(127.0.0.1)
    • 输入消息内容点击发送
  3. 环回测试:发送的消息会立即被本机接收

在这里插入图片描述

6. 关键问题解决方案

  1. 数据粘包问题:UDP本身不保证数据完整性,建议:
    • 添加消息头尾标识
    • 实现应用层协议封装
  2. 大文件传输:需分片发送并重组,示例分片方法:
// 文件分片发送(示例)
byte[] fileData = File.ReadAllBytes("test.jpg");
int chunkSize = 1024;
for (int i = 0; i < fileData.Length; i += chunkSize)
{
    int size = Math.Min(chunkSize, fileData.Length - i);
    byte[] chunk = new byte[size + 4];
    Buffer.BlockCopy(BitConverter.GetBytes(i), 0, chunk, 0, 4);
    Buffer.BlockCopy(fileData, i, chunk, 4, size);
    udpClient.Send(chunk, chunk.Length, targetIp, targetPort);
}

7. 总结

本文实现了一个基础的UDP通信上位机程序,具有以下特点:

  • 支持双向通信(发送/接收)
  • 实时显示带时间戳的通信日志
  • 自动处理跨线程UI更新
  • 完善的资源释放机制

扩展方向

  1. 增加十六进制收发功能
  2. 实现消息过滤机制
  3. 添加数据统计功能(收发计数器)
  4. 支持多网卡绑定选择

完整源码下载:【C# UDP通信上位机源码】


推荐工具

参考文献