【C# 上位机UDP通讯】

【C# 上位机UDP通讯】

    • [1. 概述](#1. 概述)
    • [2. 开发环境](#2. 开发环境)
    • [3. 功能需求](#3. 功能需求)
    • [4. 实现步骤](#4. 实现步骤)
      • [4.1 界面设计](#4.1 界面设计)
      • [4.2 UDP监听实现](#4.2 UDP监听实现)
      • [4.3 消息发送功能](#4.3 消息发送功能)
      • [4.4 线程安全日志显示](#4.4 线程安全日志显示)
      • [4.5 资源释放处理](#4.5 资源释放处理)
    • [5. 使用效果演示](#5. 使用效果演示)
    • [6. 关键问题解决方案](#6. 关键问题解决方案)
    • [7. 总结](#7. 总结)

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
    完整代码
csharp 复制代码
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端口:

csharp 复制代码
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实例发送数据:

csharp 复制代码
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:

csharp 复制代码
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资源:

csharp 复制代码
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. 大文件传输:需分片发送并重组,示例分片方法:
csharp 复制代码
// 文件分片发送(示例)
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通信上位机源码】


推荐工具:

参考文献:

相关推荐
小徐不徐说8 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
ragnwang8 小时前
Notes: Python pybind11 import C++ module
开发语言·c++·python
Wang's Blog8 小时前
Java 项目实战: 交友项目 - 搜索附近的功能概述和分析
java·开发语言·交友
骑着蜗牛撵大象3278 小时前
大模型 Agent 的沙箱护栏:gVisor 隔离、出口白名单与审计闭环
java·开发语言·jvm·安全·agent沙箱·gvisor·microvm
Dxy12393102169 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷9 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
云和数据.ChenGuang10 小时前
深入解析 Python 的 dir():从用法到 CPython 源码实现
开发语言·人工智能·python·langchain
nice_lcj52011 小时前
深入理解 Java 反射:从 Class 对象到方法调用(含性能实测 + 迷你 IOC 实战 + 面试考点)
java·开发语言·后端·面试
樱花树下的数学喵12 小时前
手写简易 STL string|C++ 字符串底层实现
开发语言·c++
jimy113 小时前
C++ 报错的 qualifiers 的意思
开发语言·c++