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

C++ Qt开发:QUdpSocket网络通信组件

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QUdpSocket组件实现基于UDP的网络通信功能。

QTcpSocket组件功能类似,QUdpSocket组件是 Qt 中用于实现用户数据报协议(UDP,User Datagram Protocol)通信的类。UDP 是一种无连接的、不可靠的数据传输协议,它不保证数据包的顺序和可靠性,但具有低延迟和简单的特点。

以下是 QUdpSocket 类的完整函数及其简要解释:

函数描述
QUdpSocket(QObject *parent = nullptr)构造函数,创建一个新的 QUdpSocket 对象。
~QUdpSocket()析构函数,释放 QUdpSocket 对象及其资源。
void bind(const QHostAddress &address, quint16 port, BindMode mode = DefaultForPlatform)将套接字绑定到指定的本地地址和端口。
void close()关闭套接字。
bool joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface = QNetworkInterface())加入多播组。
bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface = QNetworkInterface())离开多播组。
qint64 pendingDatagramSize() const返回下一个待读取的数据报的大小。
qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)读取数据报。
QByteArray readDatagram(qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)读取数据报,返回 QByteArray 对象。
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)发送数据报。
qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &address, quint16 port)发送数据报,接受 QByteArray 对象。
QAbstractSocket::SocketState state() const返回套接字的当前状态。
QAbstractSocket::SocketType socketType() const返回套接字的类型。
bool isValid() const如果套接字有效,则返回 true;否则返回 false
int error() const返回套接字的当前错误代码。
QHostAddress localAddress() const返回本地地址。
quint16 localPort() const返回本地端口。
int readBufferSize() const返回读取缓冲区的大小。
void setReadBufferSize(int size)设置读取缓冲区的大小。
QNetworkInterface multicastInterface() const返回多播组的网络接口。
void setMulticastInterface(const QNetworkInterface &iface)设置多播组的网络接口。
bool hasPendingDatagrams() const如果有待读取的数据报,则返回 true;否则返回 false
bool isReadable() const如果套接字可读,则返回 true;否则返回 false
bool isWritable() const如果套接字可写,则返回 true;否则返回 false
bool setSocketDescriptor(int socketDescriptor, QUdpSocket::SocketState socketState = ConnectedState, QIODevice::OpenMode openMode = ReadWrite)设置套接字描述符。
int socketDescriptor() const返回套接字描述符。
bool waitForReadyRead(int msecs = 30000)等待套接字可读取数据。
bool waitForBytesWritten(int msecs = 30000)等待套接字已写入指定字节数的数据。
void ignoreSslErrors(const QList<QSslError> &errors)忽略 SSL 错误。
void abort()强制关闭套接字。
QNetworkProxy proxy() const返回套接字的代理设置。
void setProxy(const QNetworkProxy &networkProxy)设置套接字的代理设置。
QString errorString() const返回套接字的错误消息字符串。

这些函数提供了在 UDP 通信中使用 QUdpSocket 的各种功能,包括绑定、发送和接收数据报、设置和获取套接字的状态等。

1.1 初始化部分

在初始化部分我们首先通过new QUdpSocket来实现创建UDP对象,QUdpSocket 构造函数的函数原型如下:

QUdpSocket::QUdpSocket(QObject * parent = nullptr)

如上构造函数创建一个新的 QUdpSocket 对象。如果提供了 parent 参数,则会将新创建的 QUdpSocket 对象添加到 parent 对象的子对象列表中,并且在 parent 对象被销毁时自动销毁 QUdpSocket 对象。如果没有提供 parent 参数,则 QUdpSocket 对象将不会有父对象,并且需要手动管理其生命周期。

初始化结束后,则下一步需要调用bind()bind() 函数是 QUdpSocket 类的一个成员函数,用于将套接字绑定到特定的本地地址和端口。它的函数原型如下:

void QUdpSocket::bind(const QHostAddress &address, quint16 port, BindMode mode = DefaultForPlatform)
  • address:要绑定的本地地址,通常是 QHostAddress::Any,表示绑定到所有可用的网络接口。
  • port:要绑定的本地端口号。
  • mode:绑定模式,指定套接字的行为。默认值是 DefaultForPlatform,表示使用平台默认的绑定模式。

该函数允许 QUdpSocket 在本地网络接口上监听传入的数据报。一旦调用了 bind() 函数,QUdpSocket 就可以接收来自指定地址和端口的数据报。

在调用 bind() 函数之后,如果成功绑定了指定的地址和端口,套接字将处于 BoundState 状态。如果出现错误,可以通过检查 error() 函数获取错误代码,并通过 errorString() 函数获取错误消息。

接着我们通过connect()函数依次绑定套接字到stateChanged状态改变信号,以及readyRead()读取信号上,这段初始化代码如下所示;

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);udpSocket=new QUdpSocket(this);// 生成随机整数 包含2000 - 不包含65534int randomInt = QRandomGenerator::global()->bounded(2000, 65534);if(udpSocket->bind(randomInt)){this->setWindowTitle(this->windowTitle() + " | 地址: " + getLocalAddress() + " 绑定端口:" + QString::number(udpSocket->localPort()));}connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));onSocketStateChange(udpSocket->state());connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}

接着切换到读取信号所对应的槽函数上,onSocketReadyRead是我们自定义的一个槽,该槽函数功能如下所示;

// 读取收到的数据报
void MainWindow::onSocketReadyRead()
{while(udpSocket->hasPendingDatagrams()){QByteArray datagram;datagram.resize(udpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);QString str=datagram.data();QString peer="[消息来自 " + peerAddr.toString()+":"+QString::number(peerPort)+"] | ";ui->plainTextEdit->appendPlainText(peer+str);}
}

首先在代码中调用pendingDatagramSize函数,pendingDatagramSize()QUdpSocket 类的一个成员函数,用于获取下一个待读取的数据报的大小。它的函数原型如下:

qint64 QUdpSocket::pendingDatagramSize() const

该函数返回一个 qint64 类型的值,表示下一个待读取的数据报的大小(以字节为单位)。如果没有待读取的数据报,或者发生了错误,该函数将返回 -1。

通常,可以在调用 readDatagram() 函数之前调用 pendingDatagramSize() 函数来获取下一个待读取的数据报的大小。这样可以为数据缓冲区分配正确大小的空间,以确保完整地读取数据报。

当有了待读取字节后,接着就可以直接通过调用readDatagram函数来从套接字中读取数据报,readDatagram()QUdpSocket 类的一个成员函数,它有几个重载形式,其中最常用的是:

qint64 QUdpSocket::readDatagram(char * data, qint64 maxSize, QHostAddress * address = nullptr, quint16 * port = nullptr)

该函数用于读取数据报并将其存储到指定的缓冲区 data 中,最多读取 maxSize 个字节的数据。可选参数 addressport 用于返回数据报的源地址和端口号。如果不需要这些信息,可以将它们设置为 nullptr

函数返回实际读取的字节数,如果发生错误,返回 -1。要查看错误信息,可以使用 error()errorString() 函数。

另外,还有一个更简单的重载形式:

QByteArray QUdpSocket::readDatagram(qint64 maxSize, QHostAddress * address = nullptr, quint16 * port = nullptr)

这个重载函数直接返回一个 QByteArray 对象,其中包含了读取的数据报。

1.2 单播与广播消息

单播(Unicast)和广播(Broadcast)是网络通信中常见的两种数据传输方式,它们在数据包的传输范围和目标数量上有所不同。

单播(Unicast)

单播是一种一对一的通信方式,其中数据包从一个发送者传输到一个接收者。在单播通信中,数据包只发送到目标主机的网络接口,并且只有目标主机能够接收和处理这个数据包。

  • 一对一通信:每个数据包只有一个发送者和一个接收者。
  • 目标明确:数据包只发送到特定的目标主机,其他主机不会接收到这个数据包。
  • 点到点通信:适用于直接通信的场景,如客户端与服务器之间的通信。

当按钮发送消息被点击后,则是一种单播模式,通常该模式需要得到目标地址与端口号,并通过调用writeDatagram来实现数据的发送,该函数通过传入三个参数,分别是发送字符串,目标地址与目标端口来实现一对一推送。

void MainWindow::on_pushButton_clicked()
{QHostAddress targetAddr(ui->lineEdit_addr->text());QString portString = ui->lineEdit_port->text();quint16 targetPort = portString.toUShort();QString msg=ui->lineEdit_msg->text();QByteArray str=msg.toUtf8();// 发送数据报udpSocket->writeDatagram(str,targetAddr,targetPort);ui->plainTextEdit->appendPlainText("[单播消息] | " + msg);
}
广播(Broadcast)

广播是一种一对多的通信方式,其中数据包从一个发送者传输到同一网络中的所有主机。在广播通信中,数据包被发送到网络中的所有主机,并且所有的主机都能够接收和处理这个数据包。

  • 一对多通信:每个数据包有一个发送者,但可以有多个接收者。
  • 目标不明确:数据包被发送到网络中的所有主机,不需要知道接收者的具体地址。
  • 广播域:在局域网中进行广播,只有在同一广播域内的主机才能接收到广播消息。
  • 网络负载:在大型网络中使用广播可能会产生大量的网络流量,影响网络性能。

当按钮广播消息被点击后,则同样是调用writeDatagram函数与,唯一的区别在于第二个参数并未指定地址,而是使用了QHostAddress::Broadcast来代替,意味着只要端口是一致的则对所有的客户推送消息,其他保持不变。

void MainWindow::on_pushButton_2_clicked()
{// 广播地址QString portString = ui->lineEdit_port->text();quint16 targetPort = portString.toUShort();QString  msg=ui->lineEdit_msg->text();QByteArray str=msg.toUtf8();udpSocket->writeDatagram(str,QHostAddress::Broadcast,targetPort);ui->plainTextEdit->appendPlainText("[广播消息] | " + msg);
}

读者可自行运行两次客户端,此时的端口将会随机分配,当指定对端端口后就可以向其发送数据,如下图所示;具体实现细节,请参考文章附件。

相关文章:

C++ Qt开发:QUdpSocket网络通信组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QUdpSocket组件实现基于UDP的网络通信…...

微信小程序小白易入门基础教程1

微信小程序 基本结构 页面配置 页面配置 app.json 中的部分配置&#xff0c;也支持对单个页面进行配置&#xff0c;可以在页面对应的 .json 文件来对本页面的表现进行配置。 页面中配置项在当前页面会覆盖 app.json 中相同的配置项&#xff08;样式相关的配置项属于 app.js…...

D. Tandem Repeats? - 思维 + 双指针

题面 分析 s s s的范围很小&#xff0c;可以 O ( n 2 ) O(n^2) O(n2)&#xff0c;在规定复杂度以内来完成枚举所有子串判断是否有满足条件的最大的子串&#xff0c;可以在第一层循环枚举子串长度 d d d&#xff0c;第二层循环枚举左右端点&#xff0c;通过双指针维护区间。对长…...

第十三届蓝桥杯省赛CC++ 研究生组

蓝桥杯2022年第十三届省赛真题-裁纸刀 蓝桥杯2022年第十三届省赛真题-灭鼠先锋 蓝桥杯2022年第十三届省赛真题-质因数个数 求个数&#xff0c;则只需要计数即可。求啥算啥&#xff0c;尽量不要搞多余操作 蓝桥杯2022年第十三届省赛真题-选数异或 蓝桥杯2022年第十三届省赛真题…...

Oracle中的commit与rollback

SQL语言分为五大类&#xff1a; DDL(数据定义语言:DataDefinitionLanguage) - Create、Alter、Drop 这些语句自动提交&#xff0c;无需用Commit提交。 DQL(数据查询语言:DataQueryLanguage) - Select 查询语句不存在是否提交问题。 DML(数据操纵语言:DataManipulationLangua…...

鸿蒙Harmony应用开发—ArkTS声明式开发(画布组件:OffscreenCanvasRenderingContext2D)

使用OffscreenCanvasRenderingContext2D在Canvas上进行离屏绘制&#xff0c;绘制对象可以是矩形、文本、图片等。离屏绘制是指将需要绘制的内容先绘制在缓存区&#xff0c;然后将其转换成图片&#xff0c;一次性绘制到canvas上&#xff0c;加快了绘制速度。 说明&#xff1a; 从…...

Redis如何实现主从复制?主从复制的作用是什么?Redis集群是如何工作的?它有哪些优点和缺点?

Redis如何实现主从复制&#xff1f;主从复制的作用是什么&#xff1f; Redis的主从复制是一种数据复制机制&#xff0c;其中一个Redis实例作为主节点&#xff08;master&#xff09;&#xff0c;而其他Redis实例作为从节点&#xff08;slave&#xff09;。主从复制的实现过程如…...

【Numpy】(2)numpy对象和random模块

numpy.array对象 numpy.array 对象是 NumPy 库的核心&#xff0c;它提供了一种高效的方式来存储和操作同质数据类型的多维数组。每个 numpy.array 对象都有一系列的属性&#xff0c;这些属性提供了关于数组的重要信息。理解这些属性对于有效地使用 NumPy 和进行数据分析是非常…...

[QJS xmake] 非常简单地在Windows下编译QuickJS!

文章目录 前言准备C编译器xmake编译包 工程准备修改版本号第一遍编译第二遍编译效果 前言 quickjs是个很厉害的东西啊&#xff0c;我一直想编译一下的&#xff0c;奈何一直没成功。现在找了点时间成功编译了&#xff0c;写篇文章记录一下。当前版本&#xff1a;2024-1-13 应该…...

Ubuntu双系统/home分区扩容

一、Windows系统中利用磁盘管理分出空闲区域&#xff0c;如果多就多分一些 二、插入安装Ubuntu的U盘启动盘&#xff0c;lenovo电脑F12&#xff08;其他电脑可选择其他类似方式&#xff09;选择U盘启动项&#xff0c;然后选择ubuntu&#xff0c;出现安装界面&#xff0c;再选择t…...

0基础学习VR全景平台篇第145篇:图层控件功能

大家好&#xff0c;欢迎观看蛙色VR官方——后台使用系列课程&#xff01;这期&#xff0c;我们将为大家介绍如何使用图层控件功能。 一.如何使用图层控件功能&#xff1f; 进入作品编辑页面&#xff0c;点击左边的控件后就可以在右边进行相应设置。 二.图层控件有哪些功能&am…...

一文看懂套利的那些事儿

我们经常在投资中都有提到套利策略&#xff0c;经常听到某某套利&#xff0c;或者借用什么套利工具&#xff0c;股票可以套利&#xff0c;基金期货期权也可以套利&#xff0c;套利到底是什么&#xff1f;套利到底是如何运用的&#xff1f; 今天我们一文解读套利市场&#xff01…...

【工具】Mermaid + 大模型画流程图

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 引入使用画TCP三次握手了解历史人物 总结 引入 最近看面试文章关于TCP三次握手和…...

内网渗透学习-环境搭建

1、环境搭建测试 虚拟机网络环境配置&#xff0c;模拟外网和内网 主机操作系统网络内网ip外网ip物理主机window10vmnet8192.168.70.1攻击机kali Linuxvmnet8192.168.70.134域控主机win server 2008 r2vmnet0192.168.52.138域成员主机win server 2k3vmnet0192.168.52.141服务器…...

el-progress渐变色

线性渐变喝环形渐变 线性渐变&#xff1a;直接修改样式根据所需颜色修改即可 ::v-deep .el-progress {.el-progress-bar {.el-progress-bar__outer {background: linear-gradient(to right#8075fd, #b87bfe)}.el-progress-bar__inner {background: linear-gradient(to right…...

DHCP在企业网的部署及安全防范

学习目标&#xff1a; 1. DHCP能够解决什么问题&#xff1f; 2. DHCP服务器如何部署&#xff1f; 3. 私接设备会带来什么问题以及如何防范&#xff1f; 给DHCP服务器配置地址&#xff1a; 地址池&#xff1a; DHCP有2种分配模式&#xff1a;全局分配和接口分配 DHCP enable...

列表的常用操作

列表的常用操作&#xff08;方法&#xff09; 列表除了可以&#xff1a; 定义使用下标索引获取值 此外列表也提供一些列功能&#xff1a;插入元素删除元素清空元素修改元素统计元素个数 等等功能&#xff0c;这些功能我们都称之为&#xff1a;列表的方法 列表的查询功能&…...

外包2月,技术退步惊现!大专生逆袭大厂,全靠这份神秘资料!

大家好&#xff0c;我是一名大专生&#xff0c;19年通过校招进入湖南某软件公司&#xff0c;从事功能测试工作已近4年。今年8月&#xff0c;我意识到长期舒适的环境让我变得不思进取&#xff0c;技术停滞不前&#xff0c;甚至因此失去了谈了2年的女朋友。我下定决心&#xff0c…...

考研失败, 学点Java打小工_Day3_卫语句_循环

1 编码规范——卫语句 表达异常分支时&#xff0c;少用if-else方式。   比如成绩判断中对于非法输入的处理&#xff1a; /*>90 <100 优秀>80 <90 良好>70 <80 一般>60 <70 及格<60 不及格*/Testpu…...

网络架构层_服务器上下行宽带

网络架构层_服务器上下行宽带 解释一 云服务器ECS网络带宽的概念、计费、安全及使用限制_云服务器 ECS(ECS)-阿里云帮助中心 网络带宽是指在单位时间&#xff08;一般指的是1秒钟&#xff09;内能传输的数据量&#xff0c;带宽数值越大表示传输能力越强&#xff0c;即在单位…...

面试算法-47-有效的括号

题目 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右…...

Android11 HID开发系统源码配置

# RK356X_ANDROID11_CUSTOM_HID ## 1.确认SDK版本。 cat .repo/manifests/include/rk356x_repository.xml <?xml version="1.0" encoding="UTF-8"?> <manifest> <project path="device/rockchip/rk356x" name="rk/dev…...

73_Pandas获取分位数/百分位数

73_Pandas获取分位数/百分位数 使用 quantile() 方法获取 pandas 中 DataFrame 或 Series 的分位数/百分位数。 目录 Quantile() 的基本用法指定要获取的分位数/百分位数&#xff1a;参数 q指定interpolation方法&#xff1a;参数interpolation 数据类型 dtype 的差异 指定行…...

力扣练习题

1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按…...

Telegraf--采集指定信息

Telegraf 采集字段解释 根据需求选取需要采集的字段,直接配置在fieldpass中,这样的好处是节约流量,更加简洁明了。下面加粗的部分是telegraf.conf中配置的指标,其他指标根据需求添加即可。 2024年3月18日10:55:41 更新说明: 添加自定义温度指标采集 CPU信息 usage_iowait:…...

Redis是如何实现持久化的?请解释RDB和AOF持久化方式的区别和优缺点。Redis是单线程还是多线程的?为什么Redis使用单线程模型仍然能保持高性能?

Redis是如何实现持久化的&#xff1f;请解释RDB和AOF持久化方式的区别和优缺点。 Redis实现持久化主要有两种方式&#xff1a;RDB&#xff08;Redis DataBase&#xff09;和AOF&#xff08;Append Only File&#xff09;。这两种方式的主要区别在于它们的持久化机制和适用场景。…...

java通过Excel批量上传数据

一、首先在前端写一个上传功能。 <template><!-- 文件上传 --><el-upload class"upload-demo" :on-change"onChange" :auto-upload"false"><el-button type"primary">上传Excel</el-button></el-up…...

VS2022 配置QT5.9.9

QT安装 下载地址&#xff1a;https://download.qt.io/archive/qt/ 下载安装后进行配置 无法运行 rc.exe 下载VS2022 官网下载 配置 1.扩展-管理扩展-下载Qt Visual Studio Tools 安装 2.安装完成后&#xff0c;打开vs2022,点击扩展&#xff0c;会发现多出了QT VS Tools,点…...

接收用户输入的数字,判断是否是质数(素数)以及输出1-100之间的所有质数

问题描述&#xff1a;接收用户输入的数字&#xff0c;判断是否是质数(素数)以及输出1-100之间的所有质数 质数的概念&#xff1a;一个大于1的自然数&#xff0c;除了1和它本身外&#xff0c;不能被其他自然数整除的数叫做质数&#xff0c;也称为素数 规定&#xff1a;1既不是…...

人脸识别AI视觉算法---豌豆云

人脸识别AI算法是一种基于计算机视觉和深度学习技术的系统&#xff0c;用于自动识别和验证人脸。 这些算法在多种领域有着广泛的应用&#xff0c;包括安全认证、身份验证、监控、社交媒体、医疗保健和零售等。 以下是有关人脸识别AI算法的技术背景和应用场景的介绍&#xff1…...

简单的视频网站能不能用dw做/谷歌google官网

我觉得docker最大的便利性体现在可以实现镜像共享&#xff0c;方便团队在同一环境下开发。当然docker的强大之处不止于此。 接下来我用一个例子来演示如何进行docker镜像共享&#xff0c;步骤如下&#xff08;Ubuntu&#xff09;&#xff1a; 准备工作&#xff1a;首先确定已经…...

wordpress登录wp-admin/今日热点新闻一览

基于双向链表的增删改查和排序&#xff08;C实现&#xff09;双向链表也叫双链表&#xff0c;是链表的一种&#xff0c;它的每个数据结点中都有两个指针&#xff0c;分别指向直接后继和直接前驱。所以&#xff0c;从双向链表中的任意一个结点开始&#xff0c;都可以很方便地访问…...

凡天网网站建设/百度搜索图片

东莞西南科技XL-LS-E太阳能航标灯采用内置转换效率高达25%的太阳能电池板一体化设计&#xff0c;配合太阳能专用磷酸铁锂电池为电源。控制电路采用微功耗单片机控制芯片&#xff0c;能更精确的控制电池充放电状态&#xff0c;同时也降低了控制电路本身能耗。光源采用特殊定制LE…...

关于做好学院网站建设的要求/百度学术论文查重官网入口

本文在研发组织管理中的位置&#xff1a; 研发组织管理--项目管理--敏捷迭代管理--每日站会 目的 1、同步信息&#xff0c;抛出问题&#xff1b;2、周知需求变更及调整&#xff1b; 时间&频次 1、每天一次固定时间, 开始时间由master安排&#xff1b;2、时长由master控制…...

辽宁网站建设找哪家/seo关键字排名

首先介绍Web服务器是什么Web服务器一般指网站服务器&#xff0c;是指驻留于因特网上某种类型计算机的程序&#xff0c;可以向浏览器等Web客户端提供文档&#xff0c;我们可以放置网站文件&#xff0c;让全世界浏览&#xff1b;可以放置数据文件&#xff0c;让全世界下载 常见的…...

网站设计怎么收费/百度网页版主页网址

如果你还想从头学起Pytest&#xff0c;可以看看这个系列的文章哦&#xff01; https://www.cnblogs.com/poloyy/category/1690628.html 前言 为了提高复用性&#xff0c;我们在写测试用例的时候&#xff0c;会用到不同的fixture&#xff0c;比如&#xff1a;最常见的登录操作&a…...