当前位置: 首页 > article >正文

C#:使用UDP协议实现数据的发送和接收

UDP(User Datagram Protocol)是一种无连接的、轻量级的传输协议,适用于对实时性要求较高的应用场景,如视频流、在线游戏等。与TCP不同,UDP不保证数据的可靠传输,但其传输效率更高。本文将详细介绍如何使用C#实现基于UDP协议的数据发送和接收,并结合代码示例解析其实现过程。

1. 概述

UDP通讯的核心是UdpClient类,它封装了UDP协议的底层操作,提供了简单易用的接口。以下是UDP通讯的基本流程:

初始化UDP客户端:绑定本地端口,准备接收数据。

接收数据:通过UdpClient.Receive方法异步接收数据。

发送数据:通过UdpClient.Send方法向目标地址发送数据。

数据处理:对接收到的数据进行解析和处理。

2. 关键技术点

2.1 UdpClient类

UdpClient是C#中用于实现UDP通讯的核心类,提供了发送和接收数据的方法。

2.2 异步接收数据

通过UdpClient.Receive方法异步接收数据,避免阻塞主线程。

2.3 数据解析

接收到的数据通常是字节数组(byte[]),需要根据协议格式进行解析。

2.4 事件机制

通过事件机制将接收到的数据传递给其他模块处理。

3. 代码实现

以下是基于UDP协议实现数据发送和接收的代码示例。

3.1 ConnectUDP类

ConnectUDP类负责初始化UDP客户端、接收数据、发送数据以及处理数据。

public class ConnectUDP
{
    private UdpClient udpClient; // UDP客户端
    private IPEndPoint endPoint; // 远程终结点
    private Thread receiveThread; // 接收数据的线程
    private bool isReceiving = true; // 控制接收线程的标志
    public MainWindow mainWindow; // 主窗体实例
    public event EventHandler<ReceiveDataEventArg> DataReceived; // 数据接收事件
    private byte[] _receivedData03; // 存储接收到的数据

    public ConnectUDP(MainWindow mainWindow)
    {
        this.mainWindow = mainWindow;
        mainWindow.DataReceived += MainWindow_DataReceived; // 订阅主窗体的事件
    }

    // 主窗体数据接收事件的处理方法
    private void MainWindow_DataReceived(byte[] data)
    {
        if (data[1] == 0x03) // 判断功能码
        {
            _receivedData03 = data; // 存储接收到的数据
        }
    }

    /// <summary>
    /// 初始化UDP客户端
    /// </summary>
    /// <param name="port">本地端口</param>
    public void InitializeUdpClient(int port)
    {
        try
        {
            endPoint = new IPEndPoint(IPAddress.Any, port); // 绑定本地端口
            udpClient = new UdpClient(endPoint);
            udpClient.Client.ReceiveTimeout = 1000; // 设置接收超时时间
            receiveThread = new Thread(new ThreadStart(ReceiveData)); // 创建接收线程
            receiveThread.IsBackground = true; // 设置为后台线程
            receiveThread.Start(); // 启动线程
        }
        catch (Exception ex)
        {
            Console.WriteLine("UDP Client Initialization Error: " + ex.Message);
        }
    }

    // 接收数据的方法
    private void ReceiveData()
    {
        while (isReceiving)
        {
            try
            {
                Byte[] receiveBytes = udpClient.Receive(ref endPoint); // 接收数据
                string receivedData = Encoding.ASCII.GetString(receiveBytes);
                if (receiveBytes != null)
                {
                    UdpSendData(GetReceiveData(receiveBytes)); // 处理并发送数据
                }
            }
            catch (SocketException)
            {
                continue; // 忽略超时异常
            }
        }
    }

    // 处理接收到的数据
    public byte[] GetReceiveData(byte[] ReceivedData)
    {
        byte[] receivedData = ReceivedData;
        byte[] SendData = null;
        if (receivedData != null && receivedData.Length > 2)
        {
            if (receivedData[1] == 0x03) // 功能码0x03:查询操作
            {
                if (_receivedData03 == null)
                {
                    // 执行查询操作
                }
                ushort dio1 = ConvertToUShort(mainWindow.GetDIO1());
                ushort dio2 = ConvertToUShort(mainWindow.GetDIO2());
                return ProcessData(_receivedData03, dio1, dio2); // 处理数据
            }
            else if (receivedData[1] == 0x06) // 功能码0x06:设置操作
            {
                ushort[] units;
                if (receivedData[3] == 0x01) // 离散量板卡1
                {
                    byte[] receiveDataBuffer = new byte[2];
                    Array.Copy(receivedData, 4, receiveDataBuffer, 0, 2);
                    units = GetUnitsFromByteArray(receiveDataBuffer);
                    mainWindow.Dispatcher.Invoke(() =>
                    {
                        mainWindow.SetDIO1Info(units, "DIO1"); // 更新UI
                    });
                    return receivedData;
                }
                else if (receivedData[3] == 0x02) // 离散量板卡2
                {
                    byte[] receiveDataBuffer = new byte[2];
                    Array.Copy(receivedData, 4, receiveDataBuffer, 0, 2);
                    units = GetUnitsFromByteArray(receiveDataBuffer);
                    mainWindow.Dispatcher.Invoke(() =>
                    {
                        mainWindow.SetDIO1Info(units, "DIO2"); // 更新前端UI
                    });
                    return receivedData;
                }
            }
        }
        return SendData;
    }

    // 发送数据的方法
    public void UdpSendData(byte[] message)
    {
        if (endPoint == null || message == null)
        {
            endPoint = new IPEndPoint(IPAddress.Any, 18081); // 目标IP和端口
            return;
        }
        try
        {
            Byte[] sendBytes = message;
            udpClient.Send(sendBytes, sendBytes.Length, endPoint); // 发送数据
            Console.WriteLine("Sent: " + message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("UDP Send Error: " + ex.Message);
        }
    }

}

3.2 主窗体(MainWindow)

主窗体负责初始化ConnectUDP并启动UDP客户端。

public partial class MainWindow : Window
{
    private ConnectUDP connectUDP;

    public MainWindow()
    {
        InitializeComponent();
        connectUDP = new ConnectUDP(this); // 初始化ConnectUDP
        connectUDP.InitializeUdpClient(18080); // 启动UDP客户端
    }
}

4. 数据传递流程详解

4.1 初始化UDP客户端

在InitializeUdpClient方法中,绑定本地端口并启动接收线程。

接收线程通过UdpClient.Receive方法异步接收数据。

4.2 接收数据

接收线程在ReceiveData方法中循环接收数据。

接收到数据后,调用GetReceiveData方法处理数据。

4.3 处理数据

根据功能码(如0x03、0x06)解析数据。

更新UI或执行其他逻辑。

4.4 发送数据

在UdpSendData方法中,将处理后的数据发送到目标地址。

5. 关键技术解析

5.1 异步接收数据

通过UdpClient.Receive方法异步接收数据,避免阻塞主线程。

5.2 数据解析

根据协议格式解析接收到的字节数组,提取有效数据。

5.3 事件机制

通过事件将接收到的数据传递给主窗体或其他模块处理。

6. 总结

本文详细介绍了如何使用C#实现基于UDP协议的数据发送和接收。通过UdpClient类,我们可以轻松实现UDP通讯,并结合事件机制实现数据的传递和处理。UDP协议适用于对实时性要求较高的场景,但其不保证数据的可靠传输。

希望这篇文章对您有所帮助!如果有任何问题,欢迎在评论区留言讨论。


http://www.kler.cn/a/593462.html

相关文章:

  • 量子计算专业书籍,做个比较
  • C++ 核心编程 ——4.9 文件操作
  • 主流NoSQL数据库类型及选型分析
  • 接口测试工具:Jmeter
  • UI设计中的模态对话框:合理使用指南
  • 举例说明 牛顿法 Hessian 矩阵
  • 【微信小程序变通实现DeepSeek支持语音】
  • Python、MATLAB和PPT完成数学建模竞赛中的地图绘制
  • Canary Capital 向 SEC 递交首个 SUI ETF 申请文件
  • Oracle ASM Failgroup故障组
  • mesh开发解析
  • Dropshare for Mac v6.1 文件共享工具 支持M、Intel芯片
  • Linux killall 命令使用详解
  • 如何解决Kafka Rebalance引起的重复消费
  • 如何在 Web Component 中优雅地使用 React
  • 解决 VS Code 中 GitHub Copilot Chat 遇到的 `claude-3.7` 模型不支持问题
  • DeepSeek + Kimi 自动生成 PPT
  • Python 爬虫(2)Web请求
  • [QT]深入理解Qt中的信号与槽机制
  • 20250319-Ragflow智能体框架实验