【C++】udp通信协议详解和示例

news2024/9/21 0:27:48

前言

UDP(‌User Datagram Protocol,‌用户数据报协议)‌是一种无连接的、‌不可靠的、‌面向数据报的传输层协议。‌它广泛应用于需要高实时性且对数据传输可靠性要求不高的场景,‌如实时音视频传输、‌在线游戏等。‌本文将详细介绍UDP通讯协议的原理、‌各关键函数的作用及其实现实例,‌并最后进行总结。‌

  • 前言
  • UDP协议原理
    • 无连接性
    • 不可靠性
    • 面向数据报
  • 相应函数
    • socket()
    • bind()
    • sendto()
    • recvfrom()
  • 示例
    • 字符串整体发送示例
      • 服务端
      • 客户端
      • 运行结果
    • 字符串分包发送示例
      • 服务端
      • 客户端
      • 运行结果
  • 总结

UDP协议原理

无连接性

UDP是无连接的协议,‌通信双方在传输数据之前不需要建立连接,‌也不需要维护连接状态。‌这种特性使得UDP在处理实时数据和快速数据传输时非常高效。‌

不可靠性

UDP不提供数据包的确认和重传机制,‌也不保证数据包的顺序性,‌因此数据传输过程中可能会出现丢包、‌重复或乱序等情况。‌UDP的设计目标之一就是降低通信的开销,‌以支持高吞吐量和低延迟的通信需求。‌

面向数据报

UDP以数据报为基本单位进行通信,‌每个数据报是一个独立的、‌完整的消息,‌具有独立的头部和数据部分。‌UDP数据报格式包括源端口号、‌目的端口号、‌长度和校验和等字段。‌
-‌源端口号(‌16 bits)‌‌:‌标识发送端的端口号。‌
-‌目的端口号(‌16 bits)‌‌:‌标识接收端的端口号。‌
-‌长度(‌16 bits)‌‌:‌表示UDP数据报的总长度,‌包括UDP头部和数据部分。‌
-‌校验和(‌16 bits)‌‌:‌用于检测数据报的完整性,‌以确保数据在传输过程中没有被损坏。‌
-‌数据(‌可变长度)‌‌:‌包含了应用程序要传输的实际数据。‌

相应函数

socket()

socket()函数用于创建一个套接字,‌它是网络通信的端点。‌对于UDP通信,‌socket()函数的第三个参数应设置为SOCK_DGRAM,‌表示创建的是数据报套接字。‌

int socket(int domain, int type, int protocol);
‌作用‌:‌创建一个新的套接字。‌

参数说明:
-‌domain‌:‌指定协议族,‌对于IPv4使用AF_INET。‌
-‌type‌:‌指定套接字类型,‌对于UDP使用SOCK_DGRAM。‌
-‌protocol‌:‌通常设置为0,‌自动选择协议。‌

bind()

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
‌作用‌:‌将套接字绑定到一个特定的地址和端口上。‌

参数说明:
-‌sockfd‌:‌由socket()返回的套接字描述符。‌
-‌addr‌:‌指向sockaddr结构的指针,‌包含地址和端口信息。‌
-‌addrlen‌:‌地址结构体的长度。‌

sendto()

‌函数原型‌:‌

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
‌作用‌:‌向指定的地址发送数据报。‌
参数说明:
-‌sockfd‌:‌套接字描述符。‌
-‌buf‌:‌指向要发送数据的缓冲区。‌
-‌len‌:‌缓冲区中数据的长度。‌
-‌flags‌:‌发送选项,‌通常设置为0。‌
-‌dest_addr‌:‌指向目标地址的sockaddr结构指针。‌
-‌addrlen‌:‌目标地址结构体的长度。‌

recvfrom()

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
‌作用‌:‌从套接字接收数据报,‌并获取发送方的地址信息。‌
参数说明:
-‌sockfd‌:‌套接字描述符。‌
-‌buf‌:‌指向接收数据的缓冲区。‌
-‌len‌:‌缓冲区的大小。‌
-‌flags‌:‌接收选项,‌通常设置为0。‌
-‌src_addr‌:‌指向sockaddr结构的指针,‌用于存储发送方的地址信息。‌
-‌addrlen‌:‌地址结构体的长度指针。‌

示例

本实例在windows 11环境下的vs2019中运行,ubuntu环境中的头文件与此不同。但各函数功能基本一样。在同一台电脑中进行发送和接受,进行两个实例。

字符串整体发送示例

服务端

#include <iostream>
#include <cstring>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "12345" // 你可以根据需要更改这个端口号,但要确保它没有被其他应用占用

int main() {
    WSADATA wsaData;
    SOCKET sock = INVALID_SOCKET;
    struct addrinfo hints, * res = NULL, * p = NULL;
    int iResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
    struct sockaddr_storage their_addr;
    socklen_t addr_size = sizeof(their_addr);

    // 初始化Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        std::cerr << "WSAStartup failed with error: " << iResult << std::endl;
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET; // 使用IPv4
    hints.ai_socktype = SOCK_DGRAM; // UDP
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags = AI_PASSIVE; // 允许绑定到任意地址

    // 解析监听地址和端口
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &res);
    if (iResult != 0) {
        std::cerr << "getaddrinfo failed with error: " << iResult << std::endl;
        WSACleanup();
        return 1;
    }

    // 创建套接字
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == INVALID_SOCKET) {
        std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
        freeaddrinfo(res);
        WSACleanup();
        return 1;
    }

    // 绑定套接字到地址和端口
    iResult = bind(sock, res->ai_addr, (int)res->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        std::cerr << "bind failed with error: " << WSAGetLastError() << std::endl;
        freeaddrinfo(res);
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(res); // 不再需要地址信息

    std::cout << "UDP Server listening on port " << DEFAULT_PORT << std::endl;

    // 接收数据
    while (true) {
        iResult = recvfrom(sock, recvbuf, recvbuflen, 0,
            (struct sockaddr*)&their_addr, &addr_size);
        if (iResult == SOCKET_ERROR) {
            std::cerr << "recvfrom failed with error: " << WSAGetLastError() << std::endl;
            closesocket(sock);
            WSACleanup();
            return 1;
        }

        recvbuf[iResult] = '\0'; // 添加空字符以创建字符串
        std::cout << "Received: " << recvbuf << std::endl;
    }

    // 注意:上面的while循环是无限循环,实际使用中你可能需要添加一些退出条件

    // 清理(虽然在这个例子中永远不会到达)
    closesocket(sock);
    WSACleanup();

    return 0;
}

客户端

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")

int main() {
    WSADATA wsaData;
    SOCKET sock = INVALID_SOCKET;
    struct addrinfo hints, * res = NULL, * p = NULL;
    int iResult;
    char sendbuf[1024] = "Hello, UDP!";
    int sendbuflen = strlen(sendbuf) + 1;

    // 初始化Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        std::cerr << "WSAStartup failed with error: " << iResult << std::endl;
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET; // 使用IPv4
    hints.ai_socktype = SOCK_DGRAM; // UDP
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags = AI_PASSIVE; // 对于发送端,这通常不是必需的,但也没有害处

    // 解析目标地址和端口
    iResult = getaddrinfo("127.0.0.1", "12345", &hints, &res);
    if (iResult != 0) {
        std::cerr << "getaddrinfo failed with error: " << iResult << std::endl;
        WSACleanup();
        return 1;
    }

    // 创建套接字
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == INVALID_SOCKET) {
        std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
        freeaddrinfo(res);
        WSACleanup();
        return 1;
    }
    while (true)
    {
        // 发送数据
        iResult = sendto(sock, sendbuf, sendbuflen, 0, res->ai_addr, (int)res->ai_addrlen);
        std::cout << "Bytes Sent: " << iResult << std::endl;
        std::cout << "(int)res->ai_addrlen: " << (int)res->ai_addrlen<< "res->ai_addr: " << res->ai_addr << std::endl;
        Sleep(100);
    }

    if (iResult == SOCKET_ERROR) {
        std::cerr << "sendto failed with error: " << WSAGetLastError() << std::endl;
        closesocket(sock);
        freeaddrinfo(res);
        WSACleanup();
        return 1;
    }

    std::cout << "Bytes Sent: " << iResult << std::endl;

    // 清理
    closesocket(sock);
    freeaddrinfo(res);
    WSACleanup();

    return 0;
}

运行结果

在这里插入图片描述

字符串分包发送示例

服务端

#include <iostream>
#include <string>
#include <vector>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

#define PORT "12345"
#define BUFFER_SIZE 6

int main() {
    WSADATA wsaData;
    int iResult;

    SOCKET recvSocket = INVALID_SOCKET;
    struct addrinfo* result = NULL, * ptr = NULL, hints;
    char recvbuf[BUFFER_SIZE];
    int recvbuflen = BUFFER_SIZE;

    std::vector<std::string> packets;

    // 初始化Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        std::cerr << "WSAStartup failed with error: " << iResult << std::endl;
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;

    // 获取本地地址信息
    iResult = getaddrinfo(NULL, PORT, &hints, &result);
    if (iResult != 0) {
        std::cerr << "getaddrinfo failed with error: " << iResult << std::endl;
        WSACleanup();
        return 1;
    }

    // 遍历地址信息列表
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
        // 创建套接字
        recvSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (recvSocket == INVALID_SOCKET) {
            std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
            continue;
        }

        // 绑定套接字到地址
        iResult = bind(recvSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            std::cerr << "bind failed with error: " << WSAGetLastError() << std::endl;
            closesocket(recvSocket);
            continue;
        }

        break;
    }

    if (recvSocket == INVALID_SOCKET) {
        std::cerr << "Unable to create socket for receiving." << std::endl;
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // 接收数据
    sockaddr_storage their_addr;
    int addr_len = sizeof(their_addr);

    while (true) {
        iResult = recvfrom(recvSocket, recvbuf, recvbuflen, 0,
            (struct sockaddr*)&their_addr, &addr_len);
        if (iResult > 0) {
            std::string packet(recvbuf, iResult);
            packets.push_back(packet);

            // 这里可以添加逻辑来检查是否接收到了完整的数据
            // 例如,如果每个包都包含长度信息或使用了某种协议来标记结束

            // 假设我们简单地等待足够的数据来重新组合字符串
            // 注意:这个示例没有实现真正的结束检测

            // 打印接收到的数据包(可选)
            std::cout << "Received " << iResult << " bytes: " << packet << std::endl;

            // 假设我们已经接收到了所有包(这里需要实现更复杂的逻辑)
            // 重新组合字符串(这里只是示例,没有实现)
            // std::string reassembledMessage = ...;

            // 如果需要,可以在这里处理reassembledMessage

        }
        else if (iResult == 0) {
            std::cout << "Connection closing..." << std::endl;
            break;
        }
        else {
            std::cerr << "recvfrom failed with error: " << WSAGetLastError() << std::endl;
            break;
        }
    }
}

客户端

#include <iostream>
#include <string>
#include <cstring>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <algorithm>

#pragma comment(lib, "ws2_32.lib")

#define PORT "12345"
#define MAX_PACKET_SIZE 6
#define min(a,b)            (((a) < (b)) ? (a) : (b))
int main() {
    WSADATA wsa;
    SOCKET sock = INVALID_SOCKET;
    struct addrinfo hints, * res;
    int iResult;

    // 初始化Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsa);
    if (iResult != 0) {
        std::cerr << "WSAStartup failed with error: " << iResult << std::endl;
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;

    // 获取本地地址信息
    iResult = getaddrinfo("127.0.0.1", PORT, &hints, &res);
    if (iResult != 0) {
        std::cerr << "getaddrinfo failed with error: " << iResult << std::endl;
        WSACleanup();
        return 1;
    }

    // 创建套接字
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == INVALID_SOCKET) {
        std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
        freeaddrinfo(res);
        WSACleanup();
        return 1;
    }

    std::string message = "这是一个CSDN中展示的示例,将这段文字分成多个包进行发送,每个包为6字节。";
    sockaddr_in their_addr;
    int addr_len = sizeof(their_addr);



    // 填充对方的地址信息
    //ZeroMemory(&their_addr, sizeof(their_addr));
    //their_addr.sin_family = AF_INET;
    //their_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 或者使用getaddrinfo获取
    //their_addr.sin_port = htons(std::stoi(PORT));

    // 发送数据
    int offset = 0;
    while (offset < message.length()) {
        int bytesToSend = min(MAX_PACKET_SIZE, static_cast<int>(message.length() - offset));
        std::string packet = message.substr(offset, bytesToSend);

        iResult = sendto(sock, packet.c_str(), packet.length(), 0,
            res->ai_addr, addr_len);
        if (iResult == SOCKET_ERROR) {
            std::cerr << "sendto failed with error: " << WSAGetLastError() << std::endl;
            closesocket(sock);
            WSACleanup();
            return 1;
        }

        offset += bytesToSend;
        std::cout << "Sent " << bytesToSend << " bytes\n";
    }

    closesocket(sock);
    WSACleanup();
    return 0;
}

运行结果

在这里插入图片描述
从接收端的结果可以看出,在最后一包的接受结果乱码了,主要原因是我们以6个字节为一包,最后只剩下5字节,造成的。

同时,也可以发现发送端发送之后就停止了,而接收端还在阻塞状态,等待着接收信息。

总结

UDP协议因其简单、‌高效的特点,‌在实时性要求高且可以容忍少量数据丢失的应用场景中得到了广泛应用。‌通过C++中的套接字API,‌我们可以方便地实现UDP通信。‌


笔者主要从事计算机视觉方面研究和开发,包括实例分割、目标检测、追踪等方向,进行算法优化和嵌入式平台开发部署。欢迎大家沟通交流、互帮互助、共同进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2051911.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python做统计图之美

Python数据分析可视化 案例效果图 import pandas as pd import matplotlib.pyplot as plt import matplotlib# 数据 data {"房型": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],"住宅类型": ["普通宅", "普通宅", "普通宅", &q…

JUC6-共享模型之不可变

目录 日期转换的问题 问题提出 思路&#xff1a;同步锁 思路&#xff1a;不可变 不可变设计 final的使用 保护性拷贝 享元模式 概述 体现 包装类 String串池 BigDecimal BigInteger DIY 原理&#xff1a;final 无状态 日期转换的问题 问题提出 下面的代码在运…

python井字棋游戏设计与实现

python实现井字棋游戏 游戏规则&#xff0c;有三个井字棋盘&#xff0c;看谁连成的直线棋盘多谁就获胜 棋盘的展现形式为 棋盘号ABC和位置数字1-9 输入A1 代表在A棋盘1号位数下棋 效果图如下 部分源码如下&#xff1a; 卫星工纵浩 白龙码程序设计&#xff0c;点 代码获取 …

Stability AI发布了单目视频转4D模型的新AI模型:Stable Video 4D

开放生成式人工智能初创公司Stability AI在3月发布了Stable Video 3D&#xff0c;是一款可以根据图像中的物体生成出可旋转的3D模型视频工具。Stability AI在7月24日发布了新一代的Stable Video 4D&#xff0c;增添了赋予3D模移动作的功能。 Stable Video 4D能在约40秒内生成8…

DBAPI如何用SQL将多表关联查询出树状结构数据(嵌套JSON格式)

场景描述 假设数据库中有3张表如下&#xff1a; 客户信息表 订单表 订单详情表 一个客户有多个订单&#xff0c;一个订单包含多个产品信息&#xff0c;客户-订单-产品就构成了3级的树状结构&#xff0c;如何查询出如下树状结构数据呢&#xff1f; [{"customer_age"…

矩阵--旋转图像

给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 &#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&a…

嵌入式Day33---Linux软件编程---网络编程

目录 一、TCP包头 1.1.源端口 1.2.目的端口 1.3.序号 1.4.确认号 1.5.数据偏移 1.6.保留 1.7.指令信号 1.SYN 2.ACK 3.FIN 4.RST 5.PSH 6.URG 1.8.窗口 1.9.校验和 1.10.紧急指针 二、TCP的过程 2.1三次握手 2.2.传输数据 ​编辑 2.3.四次挥手 ​编辑 …

SpringBoot依赖之Spring Data Redis 一 List 类型

概念 Spring Data Redis (AccessDriver) 依赖名称: Spring Data Redis (AccessDriver)功能描述: Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and muc…

[Qt][QSS][下]详细讲解

目录 1.样式属性0.前言1.盒模型(Box Model) 2.常用控件样式属性1.按钮2.复选框3.单选框4.输入框5.列表6.菜单栏7.注意 1.样式属性 0.前言 QSS中的样式属性⾮常多&#xff0c;不需要都记住&#xff0c;核⼼原则是⽤到了就去查 ⼤部分的属性和CSS是⾮常相似的 QSS中有些属性&am…

Linux CentOS手动安装Node.js(图文教程)

本章教程主要介绍如何在centos7上安装指定版本的Node.js 一、下载nodejs 前往Node.js官网&#xff0c;根据自己需要安装的版本进行下载。 官网下载地址&#xff1a;https://nodejs.org/zh-cn/download/prebuilt-binaries 本文&#xff0c;以v14.21.3版本介绍整个安装过程。 二、…

<STC32G12K128入门第十步>USB HID键盘

前言 最近公司的一款低功耗的遥控器涉及到使用USB HID的功能,就是需要将BLE蓝牙读取的IC卡的数据在通过USB接口上传到电脑的记事本上面。 一、USB HID是啥? USB HID类是USB设备的一个标准设备类,包括的设备非常多。HID类设备定义它属于人机交互操作的设备,用于控制计算机…

IDEA 导入 RocketMQ 源码

目录 前言一、RocketMQ 架构二、环境准备三、下载源码四、编译源码4.1 导入源码4.2 目录结构4.3 运行程序1. 启动 Namesrv2. 启动 Broker3. 启动 Producer4. 启动 Consumer 五、监控平台的搭建5.1 下载 console 源码5.2 IDEA 启动 前言 最近项目中有个功能需要在本地调试下 Ro…

SAM2论文核心速览

官方博客&#xff1a; https://ai.meta.com/blog/segment-anything-2/ 官方论文&#xff1a;​​​​​​https://ai.meta.com/research/publications/sam-2-segment-anything-in-images-and-videos/ 一、研究背景 研究问题&#xff1a;这篇文章要解决的问题是如何在图像和视频…

公式编辑器 -vue-formula-editor

前言 公式编辑旨在帮助用户使用可视化的前提&#xff0c;能便捷的使用平台&#xff0c;例如低代码平台使用广泛 vue-formula-editor vue-formula-editor是一款开源的Vue公式计算组件&#xff0c;可以帮助开发者快速集成公式编辑 在线体验 demo & 源码 安装 npm i vue-form…

CentOS 上安装 Java 17

要在 CentOS 上安装 Java 17&#xff0c;您可以使用多种方法。这里我将向您展示如何通过下载 Oracle 提供的 Java 开发工具包 (JDK) 或使用其他开源 JDK 版本&#xff08;如 Adoptium 或 OpenJDK&#xff09;来完成安装。 方法一&#xff1a;使用 Oracle JDK 17 下载 JDK 17&a…

HTB-BoardLight靶机笔记

BoardLight靶机笔记 概述 HTB的靶机BoardLight 靶机地址&#xff1a;https://app.hackthebox.com/machines/BoardLight 一、nmap扫描 1&#xff09;端口扫描 -sT tcp全连接扫描 --min-rate 以最低速率10000扫描 -p- 扫描全端口 sudo nmap -sT --min-rate 10000 -p- -o p…

【论文写作】怎么写一篇学术论文

文章目录 &#xff08;一&#xff09;非匀速地写论文&#xff08;二&#xff09;弄清期刊的投稿要求以及使用论文模板&#xff08;三&#xff09;论文各个部分撰写的顺序&#xff08;四&#xff09;图表比你想象中的要重要许多&#xff08;五&#xff09;结果和讨论&#xff08…

Java | Leetcode Java题解之第349题两个数组的交集

题目&#xff1a; 题解&#xff1a; class Solution {public int[] intersection(int[] nums1, int[] nums2) {Arrays.sort(nums1);Arrays.sort(nums2);int length1 nums1.length, length2 nums2.length;int[] intersection new int[length1 length2];int index 0, index…

CPU占用异常分析

文章目录 问题现象二次排查参考资料 问题现象 执行文件解压&#xff0c;执行过程中被kill掉了&#xff0c;两次均如此。 [rootlocalhost demo_2]# gzip -d demo.sql.gz Killed网上查资料&#xff0c;可能是磁盘不足、系统资源不足&#xff1b; 磁盘查看没有问题&#xff0c;内…

Matlab2021b通过CNN、CNN-LSTM模型实现对声音信号的二分类与四分类

1、利用Matlab2021b训练CNN、CNN-LSTM模型&#xff0c;对采集的一维时序信号进行分类二分类与四分类 2. 声音信号每个样本数据长度3001个采样点&#xff0c;对其进行归一化处理 3、CNN时序信号多分类执行结果截图 3.1 二分类&#xff1a; CNN模型&#xff1a; 训练集损失值…