Qt 网络编程实战

一.获取主机的网络信息

  1. 需要添加network模块
QT   += core gui network
  1. 主要涉及的类分析

QHostInfo类

  • QHostInfo::localHostName() 获取本地的主机名
  • QHostInfo::fromName(const QString &) 获取指定主机的主机信息 addresses接口

QNetworkInterface类

  • QNetworkInterface::allAddresses() 网卡所有的IP地址
  1. 项目效果

在这里插入图片描述

  1. 源码如下
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QHostInfo>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:

    //获取主机名
    void GetHostName();

    //获取IPV4
    void GetIPV4();

    //获取IPV6
    void GetIPV6();

    //清除文本内容
    void Clear_Text();

    //获取指定域名的IP地址
    void Get_DefineHost();
    void lookedUp(QHostInfo hostInfo);

    //主机所有网卡IP地址
    void GetAlladdresses();

    //所有网卡的网络信息
    void GetNetWorkInfo();

private:
    void InitConnectSignals();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QHostInfo>
#include<QNetworkInterface>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("主机的网络信息");
    InitConnectSignals();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::GetHostName()
{
    //获取当前的主机名
    QString hostname = QHostInfo::localHostName();
    ui->textEdit->append("当前的主机名为:"+hostname);

}

void MainWindow::GetIPV4()
{
    //获取当前的主机名
    QString hostname = QHostInfo::localHostName();

    //获取指定主机的主机信息
    QHostInfo hostinformation = QHostInfo::fromName(hostname);

    //Returns the list of IP addresses associated with hostName().
    //This list may be empty.
    //返回与hostName()相关联的IP地址列表。
    //该列表可能为空。
    QList<QHostAddress> addrlist = hostinformation.addresses();
    ui->textEdit->append("本机的IPV4地址如下:");

    if(!addrlist.isEmpty())
    {
        //for遍历输出
        for(int i=0;i<addrlist.size();i++)
        {
            //protocol是协议的意思
            if(addrlist[i].protocol()==QAbstractSocket::IPv4Protocol)
            {
                ui->textEdit->append(addrlist[i].toString());
            }
        }
    }

}

void MainWindow::GetIPV6()
{
    //获取当前的主机名
    QString hostname = QHostInfo::localHostName();

    //获取指定主机的主机信息
    QHostInfo hostinformation = QHostInfo::fromName(hostname);

    //Returns the list of IP addresses associated with hostName().
    //This list may be empty.
    //返回与hostName()相关联的IP地址列表。
    //该列表可能为空。
    QList<QHostAddress> addrlist = hostinformation.addresses();
    ui->textEdit->append("本机的IPV6地址如下:");

    if(!addrlist.isEmpty())
    {
        //for遍历输出
        for(int i=0;i<addrlist.size();i++)
        {
            //protocol是协议的意思
            if(addrlist[i].protocol()==QAbstractSocket::IPv6Protocol)
            {
                ui->textEdit->append(addrlist[i].toString());
            }
        }
    }
}

void MainWindow::Clear_Text()
{
    ui->textEdit->clear();
}

void MainWindow::Get_DefineHost()
{
    //获取lineEdit上的域名
    QString hostName =ui->lineEdit->text();
    if(hostName.isEmpty())
    {
        return ;
    }

    //获取域名的IPV4信息
    /*
     查找与主机名name相关联的IP地址,并返回用于查找的ID。当查找结果准备好时,
将使用QHostInfo参数调用receiver中的slot或信号成员。然后可以检查QHostInfo对象以获得查找结果。
      */
    //lookupHost(const QString &name, QObject *context, Func1 slot)
    QHostInfo::lookupHost(hostName,this,SLOT(lookedUp(QHostInfo)));
}

void MainWindow::lookedUp(QHostInfo hostInfo)
{
    //当前的主机名
    QString hostName=hostInfo.hostName();
    ui->textEdit->append("当前域名为:"+hostName+" IPV4信息如下:");

    QList<QHostAddress> addrlist = hostInfo.addresses();

    if(!addrlist.isEmpty())
    {
        for(int i=0;i<addrlist.count();i++)
        {
            if(addrlist[i].protocol()==QAbstractSocket::IPv4Protocol)
            {
                ui->textEdit->append(addrlist[i].toString());
            }
        }
    }

    /*
      常见的错误
QObject::connect: Incompatible sender/receiver arguments
        QHostInfoResult::resultsReady(QHostInfo) --> MainWindow::lookedUp(QHostInfo&)

        信号和槽的参数不匹配

     */
}

void MainWindow::GetAlladdresses()
{
    //获取网卡的所有IP信息
    ui->textEdit->append("所有网卡的IPV4信息如下:");
    QList<QHostAddress>addrlist = QNetworkInterface::allAddresses();
    if(!addrlist.isEmpty())
    {
        for(int i=0;i<addrlist.count();i++)
        {
            if(addrlist[i].protocol()==QAbstractSocket::IPv4Protocol)
            {
                ui->textEdit->append(addrlist[i].toString());
            }
        }
    }

}

void MainWindow::GetNetWorkInfo()
{
    //获取所有网卡的网络信息
    QList<QNetworkInterface>list =QNetworkInterface::allInterfaces();

    for(int i=0;i<list.count();i++)
    {
        QNetworkInterface interface = list[i];
        if(!interface.isValid())
        {
            continue;
        }

        ui->textEdit->append("设备名称:"+interface.humanReadableName());
        ui->textEdit->append("硬件地址:"+interface.hardwareAddress());


        //一个网卡,可以有多个IP地址
        QList<QNetworkAddressEntry> list2 = interface.addressEntries();
        for(int j=0; j<list2.count(); j++)
        {
              QNetworkAddressEntry entry = list2[j];
              ui->textEdit->append("\tIP地址:" + entry.ip().toString());
              ui->textEdit->append("\t子网掩码:" + entry.netmask().toString());
              ui->textEdit->append("\t广播地址: " + entry.broadcast().toString() + "\n");

         }
    }

}

void MainWindow::InitConnectSignals()
{
    //void pressed();
    connect(ui->pushButton_HostName,SIGNAL(pressed()),this,SLOT(GetHostName()));

    connect(ui->pushButton_IPV4,SIGNAL(pressed()),this,SLOT(GetIPV4()));

    connect(ui->pushButton_IPV6,SIGNAL(pressed()),this,SLOT(GetIPV6()));

    connect(ui->pushButton_Clear,SIGNAL(pressed()),this,SLOT(Clear_Text()));

    connect(ui->pushButton_DefineHost,SIGNAL(pressed()),this,SLOT(Get_DefineHost()));

    connect(ui->pushButton_Alladdresses,SIGNAL(pressed()),this,SLOT(GetAlladdresses()));

    connect(ui->pushButton_Network,SIGNAL(pressed()),this,SLOT(GetNetWorkInfo()));
}

二.TCP编程

1. server编程(服务器端实现)

  • 项目效果
    在这里插入图片描述

  • 客户端(使用的是调试助手)
    在这里插入图片描述

  • 项目源码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QLabel>
#include<QHostInfo>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    InitUI();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::InitUI()
{
    //加状态栏中添加控件
    label_first=new QLabel();
    label_second=new QLabel();
    label_third=new QLabel();
    label_four=new QLabel();

    label_first->setText("监听状态:");
    label_third->setText("套接字状态:");

    label_first->setMaximumWidth(80);
    label_third->setMaximumWidth(80);

    label_second->setMinimumWidth(100);
    label_four->setMinimumWidth(100);

    ui->statusbar->addWidget(label_first);
    ui->statusbar->addWidget(label_second);
    ui->statusbar->addWidget(label_third);
    ui->statusbar->addWidget(label_four);

    //fromName 返回指定主机的主机信息
    QHostInfo hostInfo = QHostInfo::fromName(QHostInfo::localHostName());
    QList<QHostAddress> addrlist = hostInfo.addresses();

    if(!addrlist.isEmpty())
    {
        for(int i=0;i<addrlist.count();i++)
        {
            QHostAddress address = addrlist[i];
            if(address.protocol()==QAbstractSocket::IPv4Protocol)
            {
                ui->comboBox->addItem(address.toString());
            }
        }
    }

    //本机的环回网卡的IP 127.0.0.1
    //用来做网络测试的
    ui->comboBox->addItem("127.0.0.1");

    //处理tcp通信
    tcpserver=new QTcpServer(this);

    //发现新信号就触发onNewConnection
    connect(tcpserver,SIGNAL(newConnection()),this,SLOT(onNewConnection()));





}


void MainWindow::on_actionListen_triggered()
{
    QString ip =ui->comboBox->currentText();

    //unsigned short
    quint16 port = ui->spinBox->value();
    QHostAddress addr(ip);
    //开始监听
    tcpserver->listen(addr,port);


    label_second->setText("已开始监听");
    ui->textEdit->append("开始监听,等待客户端发起连接...");

    ui->textEdit->append("服务器地址:"+tcpserver->serverAddress().toString());
    ui->textEdit->append("服务器端口:"+QString::number(tcpserver->serverPort()));

    //更改控件
    ui->actionStop->setEnabled(true);
    ui->actionListen->setEnabled(false);


}

void MainWindow::on_actionStop_triggered()
{


    //停止监听
    if(tcpserver->isListening())
    {
        tcpserver->close();
        ui->actionListen->setEnabled(true);
        ui->actionStop->setEnabled(false);
        label_second->setText("已停止监听");
    }

}

void MainWindow::on_actionClear_triggered()
{
    label_second->clear();
    label_four->clear();
    ui->textEdit->clear();
}

void MainWindow::onNewConnection()
{
    //一旦有新的连接
    //难以理解的概念:套接字,相当于客户端套接字,每当有客户端发起请求,服务器就会分配一个套接字
    //去接待

    tcpsocket=tcpserver->nextPendingConnection();//取出要服务,相当于是分配一个服务人员

    //连接成功会触发的
    connect(tcpsocket,SIGNAL(connected()),this,SLOT(onConnected()));


    //当有数据可以读的时候,我们就读数据,(使用信号槽)
    connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));


    connect(tcpsocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));

    // void stateChanged(QAbstractSocket::SocketState);
    connect(tcpsocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));

    onSocketStateChanged(tcpsocket->state());//先更新一下状态

}

void MainWindow::onSocketReadyRead()
{
    //有数据可读时
    while(tcpsocket->canReadLine())
    {
        ui->textEdit->append("[收到]"+tcpsocket->readLine());
    }

}

void MainWindow::onConnected()
{
    //刚连入成功
    ui->textEdit->append("\n客户端请求已经接入!");

    //获取客户端的地址信息
    ui->textEdit->append("客户端地址:"+tcpsocket->peerAddress().toString());

    ui->textEdit->append("客户端端口号:"+QString::number(tcpsocket->peerPort()));




}

void MainWindow::onDisconnected()
{
    ui->textEdit->append("\n客户端已断开连接");
    tcpsocket->deleteLater();//以后在删除,这样更安全
}

void MainWindow::onSocketStateChanged(QAbstractSocket::SocketState status)
{
    /*
        UnconnectedState,
        HostLookupState,
        ConnectingState,
        ConnectedState,
        BoundState,
        ListeningState,
        ClosingState
     */
    //套接字状态发生变化
    switch(status)
    {
        case QAbstractSocket::UnconnectedState:
        label_four->setText("未连接");
        break;

        case QAbstractSocket::HostLookupState:
        label_four->setText("正在查找主机名");
        break;

        case QAbstractSocket::ConnectingState:
        label_four->setText("正在连接");
        break;

        case QAbstractSocket::ConnectedState:
        label_four->setText("已连接");
        break;

        case QAbstractSocket::BoundState:
        label_four->setText("已绑定到IP地址和端口号");
        break;

        case QAbstractSocket::ListeningState:
        label_four->setText("正在监听");
        break;

        case QAbstractSocket::ClosingState:
        label_four->setText("准备关闭");
        break;
    }

}

void MainWindow::on_pushButton_clicked()
{
    //发送一行字符串
    QString msg = ui->lineEdit->text();

    //utf编码,QByteArray在功能上很像字符数组
    QByteArray str=msg.toUtf8();
    str.append('\n');

    //服务器向客户端发送数据
    tcpsocket->write(str);

}

void MainWindow::on_actionQuit_triggered()
{
    close();
}

2. 客户端实现

  • 效果展示
    在这里插入图片描述

  • 源码如下

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建了客户端的套接字对象
    tcpsocket=new QTcpSocket(this);

    //连接成功会触发的
    connect(tcpsocket,SIGNAL(connected()),this,SLOT(onConnected()));


    //当有数据可以读的时候,我们就读数据,(使用信号槽)
    connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));


    connect(tcpsocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));

    // void stateChanged(QAbstractSocket::SocketState);
    connect(tcpsocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));

    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onConnected()
{
    //peerAddress对等地址
    //打印服务器的地址
    ui->plainTextEdit->appendPlainText("已连接到服务器!");
    ui->plainTextEdit->appendPlainText("---服务器地址:"+
            tcpsocket->peerAddress().toString());

    ui->plainTextEdit->appendPlainText("---服务器端口:"+
                                       QString::number(tcpsocket->peerPort()));
}

void MainWindow::onDisconnected()
{
    ui->plainTextEdit->appendPlainText("服务器的连接已经断开");
    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);
}

void MainWindow::onSocketStateChanged(QAbstractSocket::SocketState status)
{
    //这和服务器端的判断一样的
}

void MainWindow::onSocketReadyRead()
{
    while(tcpsocket->canReadLine())
    {
        ui->plainTextEdit->appendPlainText("[收到]"+tcpsocket->readLine());
    }
}


void MainWindow::on_actionConnect_triggered()
{
    QString ip = ui->lineEditIP->text();
    quint16 port=ui->spinBoxPort->value();

    tcpsocket->connectToHost(ip,port);
}

void MainWindow::on_actionDisconnect_triggered()
{
    if(tcpsocket->state()==QAbstractSocket::ConnectedState)
    {
        //从主机那断开
        tcpsocket->disconnectFromHost();
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{

    if(tcpsocket->state()==QAbstractSocket::ConnectedState)
    {
        //从主机那断开
        tcpsocket->disconnectFromHost();
    }

    event->accept();//不调用这个窗口就不会关闭

    //event->ignore();这个窗口就不关闭
}

void MainWindow::on_actionClear_triggered()
{
    ui->plainTextEdit->clear();
}

void MainWindow::on_actionQuit_triggered()
{
    close();
}

void MainWindow::on_pushButton_clicked()
{
    QString msg = ui->lineEditSend->text();
    QByteArray str=msg.toUtf8();
    str.append('\n');

    tcpsocket->write(str);

    ui->plainTextEdit->appendPlainText("[发送]"+msg);
    ui->lineEditSend->clear();
    ui->lineEditSend->setFocus();//设置光标聚焦
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis---9---集群(cluster)

将新增的6387节点&#xff08;空槽号&#xff09;作为master节点加入原集群 Redis—9—集群&#xff08;cluster&#xff09; 是什么 定义 ​ 由于数据量过大&#xff0c;单个Master复制集难以承担&#xff0c;因此需要对多个复制集进行集群&#xff0c;形成水平扩展每个复…

电脑f盘的数据回收站清空了能恢复吗

随着信息技术的飞速发展&#xff0c;电脑已成为我们日常生活和工作中不可或缺的设备。然而&#xff0c;数据的丢失或误删往往会给人们带来极大的困扰。尤其是当F盘的数据在回收站被清空后&#xff0c;许多人会陷入绝望&#xff0c;认为这些数据已无法挽回。但事实真的如此吗&am…

【C语言】自定义类型:联合和枚举

前言 前面我们学习了一种自定义类型&#xff0c;结构体&#xff0c;现在我们学习另外两种自定义类型&#xff0c;联合 和 枚举。 目录 一、联合体 1. 联合体类型的声明 2. 联合体的特点 3. 相同成员联合体和结构体对比 4. 联合体大小的计算 5. 用联合体判断当前机…

AI Earth应用—— 在线使用sentinel数据VV和VH波段进行水体提取分析(昆明抚仙湖、滇池为例)

AI Earth 本文的主要目的就是对水体进行提取,这里,具体的操作步骤很简单基本上是通过,首页的数据检索,选择需要研究的区域,然后选择工具箱种的水体提取分析即可,剩下的就交给阿里云去处理,结果如下: 这是我所选取的一景影像: 详情 卫星: Sentinel-1 级别: 1 …

利用redis数据库管理代理库爬取cosplay网站-cnblog

爬取cos猎人 数据库管理主要分为4个模块&#xff0c;代理获取模块&#xff0c;代理储存模块&#xff0c;代理测试模块&#xff0c;爬取模块 cos猎人已经倒闭&#xff0c;所以放出爬虫源码 api.py 为爬虫评分提供接口支持 import requests import concurrent.futures import …

dependencyManagement的作用、nacos的学习

使用SpringCloudAlibaba注意各组件的版本适配 SpringCloudAlibaba已经包含了适配的各组件&#xff08;nacos、MQ等&#xff09;的版本号&#xff0c;也是一个版本仲裁者&#xff0c;但是可能已经有了父项目Spring-Boot-Starter-Parent这个版本仲裁者&#xff0c;又不能加多个父…

Mongodb oplog的作用及如何评估和更改保留时间

作者介绍&#xff1a;老苏&#xff0c;10余年DBA工作运维经验&#xff0c;擅长Oracle、MySQL、PG数据库运维&#xff08;如安装迁移&#xff0c;性能优化、故障应急处理等&#xff09; 公众号&#xff1a;老苏畅谈运维 欢迎关注本人公众号&#xff0c;更多精彩与您分享。oplog …

硅纪元视角 | 国内首款鸿蒙人形机器人“夸父”开启应用新篇章

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

景区气象站:守护旅行安全的智能向导

在繁忙的现代社会&#xff0c;人们越来越渴望逃离城市的喧嚣&#xff0c;寻找一处宁静的自然之地放松身心。景区&#xff0c;作为大自然与人类文明交织的瑰宝&#xff0c;吸引了无数游客前来探访。然而&#xff0c;多变的天气往往给游客的旅行带来不确定性。 景区气象站&#x…

Java跳出循环的四种方式

1、continue,break,return continue&#xff1a;跳出当前层循环的当前语句&#xff0c;执行当前层循环的下一条语句。   continue标签 break&#xff1a;跳出当前层循环。 break标签&#xff1a;多层循环时&#xff0c;跳到具体某层循环。 return&#xff1a;结束所有循环…

微观特征轮廓尺寸测量:光学3D轮廓仪、共焦显微镜与台阶仪的应用

随着科技进步&#xff0c;显微测量仪器以满足日益增长的微观尺寸测量需求而不断发展进步。多种高精度测量仪器被用于微观尺寸的测量&#xff0c;其中包括光学3D表面轮廓仪&#xff08;白光干涉仪&#xff09;、共聚焦显微镜和台阶仪。有效评估材料表面的微观结构和形貌&#xf…

如何选择一家适合自己的商城源码?

商城源码的选择取决于多个因素&#xff0c;包括商城的功能需求、稳定性、易用性、可定制性以及价格等。启山智软作为在市场上被广泛认可且表现优异的商城源码提供商&#xff0c;具有以下的特点和优势&#xff1a; 特点①&#xff1a;国内知名的B2B2C开源商城源码系统&#xff…

AI助手崛起:开发者的新伙伴还是未来替代者?

你好&#xff0c;我是三桥君。 自从 ChatGPT 问市以来&#xff0c;AI 将取代开发者的声音不绝于耳&#xff0c;至今还是互联网异常火热的问题。 在软件开发领域&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;正在改变开发者的工作方式。无论是代码生成、错误检测还是…

笔记15:while语句编程练习

练习一&#xff1a; 编写程序&#xff0c;求 2^24^26^2...n^2? -直到累加和大于或等于 10000 为止&#xff0c;输出累加和 -输出累加式中的项数&#xff0c;以及最大的数 n #include<stdio.h> int main() {int sum 0;int i 1;int n 0;while(sum < 10000)//将sum…

Leetcode - 周赛404

目录 一&#xff0c;3200. 三角形的最大高度 二&#xff0c;3201. 找出有效子序列的最大长度 I 三&#xff0c;3202. 找出有效子序列的最大长度 II 四&#xff0c;3203. 合并两棵树后的最小直径 一&#xff0c;3200. 三角形的最大高度 本题直接模拟&#xff0c;分别计算一下…

极简通俗VAE

一、VAE 背景&#xff1a;VAE什么变分自编码器&#xff0c;听起来起名都头大&#xff0c;用大白话告诉你。 把一个复杂图片压缩成两个参数&#xff0c;用这个参数采样再复原。 这个简单的东西是两个参数&#xff0c;均值和方差&#xff0c;用&#xff08;0&#xff0c;1&…

C语言_练习题

求最小公倍数 思路&#xff1a;假设两个数&#xff0c;5和7&#xff0c;那么最小至少也要7吧&#xff0c;所以先假定最小公倍数是两个数之间较大的&#xff0c;然后看7能不能同时整除5和7&#xff0c;不能就加1继续除 int GetLCM(int _num1, int _num2) {int max _num1>_n…

web学习笔记(八十)

目录 1.小程序实现微信一键登录 2. 小程序的授权流程 3.小程序配置vant库 4.小程序配置分包 5.小程序配置独立分包 6.小程序分包预下载 1.小程序实现微信一键登录 要先实现小程序一键登录首先我们需要给按钮设置一个绑定事件&#xff0c;然后在绑定事件内部通过wx.login…

phpexcel导入导出

前言&#xff1a; 如果你到处的excel软件打开有问题&#xff0c;下面有介绍解决办法 导入 1. composer init 初始化 2. 下载phpspreadsheet 这里需要注意php版本&#xff0c;需要大于7.2 composer require phpoffice/phpspreadsheet3. 编写代码 <?php require vendo…

Vue3+.NET6前后端分离式管理后台实战(二十七)

1&#xff0c;Vue3.NET6前后端分离式管理后台实战(二十七)