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

【QT5】<总览五> QT多线程、TCP/UDP

文章目录

前言

一、QThread多线程

二、QT中的TCP编程

1. TCP简介

2. 服务端程序编写

3. 客户端程序编写

4. 服务端与客户端测试

三、QT中的UDP编程

1. UDP简介

2. UDP单播与广播程序


前言

承接【QT5】<总览四> QT常见绘图、图表及动画。若存在版权问题,请联系作者删除!


一、QThread多线程

1. 作用:创建多线程,防止应用程序界面卡顿。

2. 主要操作:

  • ①创建的类需要继承QThread类。
  • ②重写run函数,新建的线程会执行run函数。
  • ③线程开启:对象调用start方法,使线程执行run函数。
  • ④线程终止:对象调用terminate方法,使线程不再执行run函数。
  • ⑤线程销毁:动态申请new需要调用deleteLater方法销毁线程对象。(该函数可以放置于run函数内,当run函数执行完毕后就会销毁该线程对象,防止内存泄漏)注意:尽量少用静态申请栈空间的方式创建线程对象,因为很可能该对象销毁时线程仍在执行,就会报错。

3. 实例演示:创建两个按钮,一个按钮点击时创建新线程,另一个按钮点击时终止新线程。

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QThread>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE//自定义的线程类
class MyThread : public QThread
{Q_OBJECTpublic:MyThread(QWidget *parent = nullptr){Q_UNUSED(parent)//防止编译器警告}~MyThread(){qDebug("线程销毁");}void run() override{qDebug("线程开始");sleep(5);//QThread里才有该方法qDebug("线程停止");deleteLater();//销毁线程}
};//Widget类
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;MyThread *mythread;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}//“线程开始”按钮的槽函数
void Widget::on_pushButton_clicked()
{mythread = new MyThread;mythread->start();
}//“线程终止”按钮的槽函数
void Widget::on_pushButton_2_clicked()
{//若线程没有完成,则终止if (!mythread->isFinished())mythread->terminate();
}

【3】运行效果:

  • ①当我们点击“线程开始”按钮后,控制台打印“线程开始”,五秒后控制台打印“线程停止”和“线程销毁”。
  • ②当我们点击“线程开始”按钮后,控制台打印“线程开始”,当我们在五秒内点击“线程结束”按钮,控制台什么都没有打印。

二、QT中的TCP编程

1. TCP简介

  • TCP是面向连接的可靠的基于字节流的传输层通信协议。
  • TCP的服务端和客户端通信首先必须建立连接
  • 建立连接方式:服务端监听某个端口,当有客户端通过ip和port连接时,就会创建一个socket连接,之后就可以互发数据了。
  • QT中将socket视为输入输出流,数据的收发是通过read()write()来进行,而不是常见的send和recv。

----------------------------接下来,我们以一个实例来解析服务端和用户端程序编写-------------------------

2. 服务端程序编写

2.1 编写步骤:

【1】配置:①pro文件中添加network;②添加头文件<QTcpServer>和<QTcpSocket>。

【2】创建服务端对象:QTcpServer *tcpServer;(具体分配空间在构造函数中)

【3】服务端-客户端的信号槽连接:connect(tcpServer, SIGNAL(newConnection()), this, SLOT(mNewConnection()));

【4】编写【3】中的槽函数mNewConnection():

  • ①获取客户端对象:QTcpSocket *tmpTcpSocket = tcpServer->nextPendingConnection();
  • ②获取客户端信息:
    • 获取客户端ip:tmpTcpSocket->peerAddress().toString();
    • 获取客户端port:tmpTcpSocket->peerPort();
  • ③创建信号槽来处理客户端的连接状态:connect(tmpTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
  • ④创建信号槽来接收客户端发送的信息:connect(tmpTcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));

【5】编写【4】中的槽函数mStateChanged(...):用switch-case结构来处理连接状态,当状态为断开连接时,删除当前调用的客户端对象。

【6】编写【4】中的槽函数receiveMessage():调用tmpTcpSocket->readAll()来获取客户端发送的信息。

【7】创建函数来给客户端发送数据:内部调用"客户端对象.write("写入的内容")"。

【8】开始监听:调用tcpServer->listen(QHostAddress("192.168.124.151"), 9999); 监听ip为192.168.124.151,port为9999。

2.2 编写代码:

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void mNewConnection();void receiveMessage();void mStateChanged(QAbstractSocket::SocketState socketState);void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;QTcpServer *tcpServer;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"/************************************************************ @函数名:Widget* @功  能:构造函数---创建服务端对象,与客户端连接* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("服务端");//创建对象,与客户端连接tcpServer = new QTcpServer(this);connect(tcpServer, SIGNAL(newConnection()), this, SLOT(mNewConnection()));
}/************************************************************ @函数名:~Widget* @功  能:析构函数* @参  数:无* @返回值:无*********************************************************/
Widget::~Widget()
{delete ui;
}/************************************************************ @函数名:mNewConnection* @功  能:槽函数---若客户端发起连接,服务端连接客户端* @参  数:无* @返回值:无*********************************************************/
void Widget::mNewConnection()
{//获取客户端QTcpSocket *tmpTcpSocket = tcpServer->nextPendingConnection();//打印客户端的ip和portQString ipAddr = tmpTcpSocket->peerAddress().toString();quint16 port = tmpTcpSocket->peerPort();ui->textBrowser->append("客户端的ip地址:" + ipAddr);ui->textBrowser->append("客户端的端口:" + QString::number(port));//处理客户端连接状态,接收客户端发送的数据connect(tmpTcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));connect(tmpTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
}/************************************************************ @函数名:receiveMessage* @功  能:槽函数---服务端接收客户端发送的数据* @参  数:无* @返回值:无*********************************************************/
void Widget::receiveMessage()
{QTcpSocket *tmpTcpSocket = (QTcpSocket*)sender();ui->textBrowser->append("客户端:" + tmpTcpSocket->readAll());
}/************************************************************ @函数名:mStateChanged* @功  能:槽函数---服务端处理客户端的连接状态* @参  数:socketState---客户端连接状态* @返回值:无*********************************************************/
void Widget::mStateChanged(QAbstractSocket::SocketState socketState)
{QTcpSocket *tmpTcpSocket = (QTcpSocket*)sender();//处理状态,删除断开的QTcpSocket对象switch (socketState) {case QAbstractSocket::UnconnectedState://断开连接,删除对象ui->textBrowser->append("客户端断开连接");tmpTcpSocket->deleteLater();break;case QAbstractSocket::ConnectedState://已连接ui->textBrowser->append("客户端已连接");break;default:break;}
}/************************************************************ @函数名:on_pushButton_3_clicked* @功  能:按钮"发送消息"的槽函数,将文本信息发送给所有客户端* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_3_clicked()
{QList <QTcpSocket*> clients = tcpServer->findChildren<QTcpSocket*>();for (int i = 0; i < clients.length(); ++i) {clients[i]->write(ui->lineEdit->text().toUtf8());}
}/************************************************************ @函数名:on_pushButton_clicked* @功  能:按钮"开始监听"的槽函数,监听指定的ip和port* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_clicked()
{tcpServer->listen(QHostAddress("192.168.124.151"), 9999);
}/************************************************************ @函数名:on_pushButton_2_clicked* @功  能:按钮"停止监听"的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_2_clicked()
{tcpServer->close();
}

3. 客户端程序编写

3.1 编写步骤:

【1】配置:①pro文件中添加network;②添加头文件<QTcpSocket>和<QHostAddress>。

【2】创建客户端对象:QTcpSocket *tcpSocket;(具体分配空间在构造函数中)

【3】创建信号槽来处理客户端的连接状态:connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(mStateChanged(QAbstractSocket::SocketState)));

【4】创建信号槽来接收客户端发送的信息:connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));

【5】编写【3】中的槽函数mStateChanged(...):switch-case处理。

【6】编写【4】中的槽函数receiveMessage(): 调用tcpSocket->readAll().

【7】创建函数来给服务端发送数据:内部调用"客户端对象.write("写入的内容")"。

【8】启动连接服务端:调用tcpSocket->connectToHost(QHostAddress("192.168.124.151"), 9999);

【9】断开连接服务端:调用tcpSocket->disconnectFromHost();

3.2 编写代码:

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void receiveMessage();void mStateChanged(QAbstractSocket::SocketState socketstate);void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;QTcpSocket *tcpSocket;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"/************************************************************ @函数名:Widget* @功  能:构造函数---创建客户端对象,与服务端连接* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{//ui部分ui->setupUi(this);this->setWindowTitle("客户端");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);//tcp部分tcpSocket = new QTcpSocket(this);connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
}/************************************************************ @函数名:~Widget* @功  能:析构函数* @参  数:无* @返回值:无*********************************************************/
Widget::~Widget()
{delete ui;
}/************************************************************ @函数名:receiveMessage* @功  能:槽函数---客户端接收服务端发送的数据* @参  数:无* @返回值:无*********************************************************/
void Widget::receiveMessage()
{ui->textBrowser->append("服务端:" + tcpSocket->readAll());
}/************************************************************ @函数名:mStateChanged* @功  能:槽函数---客户端连接状态改变的处理* @参  数:socketstate---当前连接状态* @返回值:无*********************************************************/
void Widget::mStateChanged(QAbstractSocket::SocketState socketstate)
{switch (socketstate) {case QAbstractSocket::UnconnectedState:ui->textBrowser->append("与服务端断开连接");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);break;case QAbstractSocket::ConnectedState:ui->textBrowser->append("与服务端成功连接");ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);break;default:break;}
}/************************************************************ @函数名:on_pushButton_3_clicked* @功  能:"发送消息"按钮的槽函数,必须连接了服务端才发送* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_3_clicked()
{if (tcpSocket->state() == QAbstractSocket::ConnectedState){tcpSocket->write(ui->lineEdit->text().toUtf8());}else {ui->textBrowser->append("请先连接服务端!");}
}/************************************************************ @函数名:on_pushButton_clicked* @功  能:"连接服务端"按钮的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_clicked()
{tcpSocket->connectToHost(QHostAddress("192.168.124.151"), 9999);
}/************************************************************ @函数名:on_pushButton_2_clicked* @功  能:"断开服务端"按钮的槽函数* @参  数:无* @返回值:无*********************************************************/
void Widget::on_pushButton_2_clicked()
{tcpSocket->disconnectFromHost();
}

4. 服务端与客户端测试

4.1 注意事项:

  • 服务端中的"开始监听"和"停止监听"应该设置成互斥的。方法一:在ui设计器里将它们添加到一个按钮组,然后选中"exclusive",将它们的"checkable"勾选上,再将"停止监听"按钮的"checked"勾选。方法二:使用代码ui->pushButton->setEnable(对/错);实现它们逻辑的互斥。
  • 客户端中的"连接服务端"和"断开服务端"应该用上述的方法二实现互斥。
  • 在服务端中,当客户端断开连接时,直接调用delete可能会出错(其他地方可能还在用这个变量)。因此,应当使用tmpTcpSocket.deleteLater(); 来删除客户端对象。

4.2 运行效果:


三、QT中的UDP编程

1. UDP简介

  • 是一个轻量级的,不可靠的,面向数据报的无连接协议。
  • 通常音频、视频和普通数据在传送时使用 UDP 较多。
  • UDP 消息传送有三种模式:单播、广播和组播三种模式。

2. UDP单播与广播程序

2.1 编写步骤:

【1】配置:①pro文件中添加network;②添加头文件<QUdpSocket>。

【2】创建UDP对象:QUdpSocket *udpSocket;(具体分配空间在构造函数中)

【3】编写函数绑定端口:调用udpSocket->bind(端口号);

【4】编写函数解除绑定:调用udpSocket->abort();

【5】“发送-接收”的信号槽连接:connect(udpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));

【6】编写【5】中的receiveMessage来获取接收的数据:内部调用udpSocket->readDatagram(mesg.data(), mesg.size(), &receiveAddress, &port);

【7】编写函数来单播发送数据:调用udpSocket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress("127.0.0.1"), 9999);

【8】编写函数来广播发送数据:与【7】类似,只是将倒数第二个参数换成QHostAddress::Broadcast。要广播几个ip和端口,就调用几次writeDatagram。

【8】要想获取当前连接的状态,操作和TCP中的一样。

2.2 实例代码:

【1】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void receiveMessage();void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_2_clicked();void on_pushButton_4_clicked();private:Ui::Widget *ui;QUdpSocket *udpSocket;
};
#endif // WIDGET_H

【2】widget.cpp:

#include "widget.h"
#include "ui_widget.h"/* 构造函数 */
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);//创建udp对象udpSocket = new QUdpSocket(this);connect(udpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));
}/* 析构函数 */
Widget::~Widget()
{delete ui;
}/* 接收信息的槽函数*/
void Widget::receiveMessage()
{QByteArray mesg;mesg.resize(udpSocket->pendingDatagramSize());QHostAddress receiveAddress;quint16 port;while (udpSocket->hasPendingDatagrams()) {udpSocket->readDatagram(mesg.data(), mesg.size(), &receiveAddress, &port);//保存接收的数据ui->textBrowser->append("接收来自:" + receiveAddress.toString() + ", 端口:" + QString::number(port));ui->textBrowser->append("接收信息:" + mesg);}
}/* 发送信息按钮的槽函数 */
void Widget::on_pushButton_3_clicked()
{udpSocket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress("127.0.0.1"), 9999);ui->textBrowser->append("发送信息:" + ui->lineEdit->text().toUtf8());
}/* 绑定端口按钮的槽函数 */
void Widget::on_pushButton_clicked()
{udpSocket->bind(9999);ui->textBrowser->append("当前绑定端口:" + QString::number(9999));ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);
}/* 解除绑定按钮的槽函数 */
void Widget::on_pushButton_2_clicked()
{udpSocket->abort();ui->textBrowser->append("解除绑定");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);
}/* 广播信息按钮的槽函数 */
void Widget::on_pushButton_4_clicked()
{udpSocket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress::Broadcast, 9999);ui->textBrowser->append("发送信息:" + ui->lineEdit->text().toUtf8());
}

【3】ui设计器:

【4】运行效果:双开该程序,每次新运行程序前修改一下绑定的端口号并编译。同时,这两个端口号需要对应才能显示单播的效果。

相关文章:

【QT5】<总览五> QT多线程、TCP/UDP

文章目录 前言 一、QThread多线程 二、QT中的TCP编程 1. TCP简介 2. 服务端程序编写 3. 客户端程序编写 4. 服务端与客户端测试 三、QT中的UDP编程 1. UDP简介 2. UDP单播与广播程序 前言 承接【QT5】&#xff1c;总览四&#xff1e; QT常见绘图、图表及动画。若存在…...

fastadmin/thinkPHPQueue消息队列详细教程

thinkphp-queue 是thinkphp 官方提供的一个消息队列服务,它支持消息队列的一些基本特性: 消息的发布,获取,执行,删除,重发,失败处理,延迟执行,超时控制等队列的多队列, 内存限制 ,启动,停止,守护等消息队列可降级为同步执行1、通过composer安装thinkPHP消息队列 …...

社区新标准发布!龙蜥社区标准化 SIG MeetUp 圆满结束

5 月 31 日&#xff0c;「龙蜥社区“走进系列”」第 9 期之走进阿里云于北京圆满结束。来自阿里云、浪潮信息、红旗软件、中兴通讯|中兴新支点、中科曙光、中科方德、统信软件、麒麟软件、万里红、普华基础软件、飞腾信息、凝思、申威、新华三等公司的 30 余位专家出席会议。会…...

快速开始一个go程序(极简-快速入门)

一、 实验介绍 1.1 实验简介 为了能更高效地使用语言进行编码&#xff0c;Go 语言有自己的哲学和编程习惯。Go 语言的设计者们从编程效率出发设计了这门语言&#xff0c;但又不会丢掉访问底层程序结构的能力。设计者们通过一组最少的关键字、内置的方法和语法&#xff0c;最终…...

HTTPS缺失?如何轻松解决IP地址访问时的“不安全”警告

一、问题现象 如果访问网站时出现以下任何一种情况&#xff0c;则说明该网站需要立即整改&#xff1a; 1.浏览器地址栏那里出现“不安全”字样&#xff1b; 2.小锁标志被红叉&#xff08;&#xff09;、斜线&#xff08;&#xff3c;&#xff09;等标志为不可用&#xff1b;…...

验证码识别接口、多种样式验证码识别接口、中英文验证码识别接口

验证码识别接口、多种样式验证码识别接口、中英文验证码识别接口 本文提供一个基于OCR和机器学习的验证码识别接口&#xff0c;能够识别较复杂的中文、英文验证码&#xff0c;在OCR的基础上针对验证码进行算法优化。本接口是收费的&#xff08;最低0.5分1次调用&#xff0c;试…...

测试bert_base不同并行方式下的推理性能

测试bert_base不同并行方式下的推理性能 一.测试数据二.测试步骤1.生成bert配置文件2.安装依赖3.deepspeed 4卡tp并行4.FSDP 4卡并行5.手动将权值平均拆到4张卡,单进程多卡推理6.手动切分成4份,基于NCCL实现pipeline并行 本文测试了bert_base模型在不同并行方式下的推理性能 约…...

FFMpeg解复用流程

文章目录 解复用流程图复用器与解复用器小结 解复用流程图 流程图&#xff0c;如上图所示。 复用器与解复用器 复用器&#xff0c;就是视频流&#xff0c;音频流&#xff0c;字幕流&#xff0c;其他成分&#xff0c;按照一定规则组合成视频文件&#xff0c;视频文件可以是mp4…...

438. 找到字符串中所有字母异位词

题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的异位词的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词指由相同字母重排列形成的字符串&#xff08;包括相同的字符串&#xff09;。 示例 1: 输入: s "cbaebabacd", p &q…...

【Qt 快速入门(三)】- Qt信号和槽

目录 Qt 快速入门&#xff08;三&#xff09;- Qt信号和槽Qt信号和槽详解信号和槽的基本概念信号槽连接 信号和槽的声明与定义连接信号和槽信号和槽的高级特性自动参数匹配信号与信号连接lambda 表达式作为槽自定义信号和槽 信号和槽的线程支持跨线程连接 信号和槽的生命周期管…...

Debain12 离线安装docker

官网教程&#xff1a;https://docs.docker.com/engine/install/debian/ 步骤 1. 解压 docker-deb.7z 安装包并上传Linux &#xff08;资源在PC端文章顶部&#xff09; 2. 安装 .deb 包 sudo dpkg -i ./containerd.io_<version>_<arch>.deb \./docker-ce_<vers…...

C++day5

思维导图 搭建一个货币的场景&#xff0c;创建一个名为 RMB 的类&#xff0c;该类具有整型私有成员变量 yuan&#xff08;元&#xff09;、jiao&#xff08;角&#xff09;和 fen&#xff08;分&#xff09;&#xff0c;并且具有以下功能&#xff1a; (1)重载算术运算符 和 -…...

SHELL脚本学习(六) 呈现数据

一、标准文件描述符 linux系统会将每个对象当作文件来处理&#xff0c;包括输入和输出。linux用文件描述符来描述每个对象。文件描述符是一个非负整数&#xff0c;唯一会标识的是打开的文件。每个进程一次最多能打开9个文件描述符。处于特殊目的&#xff0c;bash shell保留了前…...

计算机网络:网络层 - IPv4数据报 ICMP协议

计算机网络&#xff1a;网络层 - IPv4数据报 & ICMP协议 IPv4数据报[版本 : 首部长度 : 区分服务 : 总长度][标识 : 标志 : 片偏移][生存时间 : 协议 : 首部检验和][可变部分 : 填充字段] ICMP协议 IPv4数据报 一个IPv4数据报&#xff0c;由首部和数据两部分组成&#xff…...

【需求设计】软件概要设计说明怎么写?概要设计说明书实际项目案例(63页Word直接套用)

软件概要设计说明书书写要点可以归纳为以下几个方面&#xff0c;以确保文档的准确性、完整性和可读性&#xff1a; 引言 目的&#xff1a;介绍编写该文档的目的、主要内容及目标读者。 背景&#xff1a;说明被开发软件的名称、项目提出者、开发者等背景信息。 需求概述&#xf…...

网络编程2----UDP简单客户端服务器的实现

首先我们要知道传输层提供的协议主要有两种&#xff0c;TCP协议和UDP协议&#xff0c;先来介绍一下它们的区别&#xff1a; 1、TCP是面向连接的&#xff0c;UDP是无连接的。 连接的本质是双方分别保存了对方的关键信息&#xff0c;而面向连接并不意味着数据一定能正常传输到对…...

服务架构的设计原则

墨菲定律与康威定律 在系统设计的时候&#xff0c;可以依据于墨菲定律 任何事情都没有表面上看起来那么简单所有的事情都会比你预计的时间长可能出错的事总会出错担心的某一个事情的发送&#xff0c;那么它就更有可能发生 在系统划分的时候&#xff0c;可以依据康威定律 系…...

Day 14:2938. 区分黑球和白球

Leetcode 2938. 区分黑球和白球 桌子上有 n 个球&#xff0c;每个球的颜色不是黑色&#xff0c;就是白色。 给你一个长度为 n 、下标从 0 开始的二进制字符串 s&#xff0c;其中 1 和 0 分别代表黑色和白色的球。 在每一步中&#xff0c;你可以选择两个相邻的球并交换它们。 返…...

部署YUM仓库及NFS共享服务

YUM概述 YUM 基于RPM包构建的软件更新机制 可以自动解决依赖关系 所有软件包由集中的YUM软件仓库提供 YUM只允许一个程序运行&#xff0c;虽然不影响命令的使用。DNF后&#xff0c;允许多个程序允许 YUM的配置文件在/etc/yum.conf 网络源&#xff08;所有以repo为结尾都是源&am…...

web学习笔记(六十五)

目录 1. Hash模式和History模式 2. 导航守卫 3. 路由元信息 4.路由懒加载 1. Hash模式和History模式 Hash模式&#xff08;哈希模式&#xff09;和History模式&#xff08;历史模式&#xff09;是匹配路由的两种模式&#xff0c;一般默认配置Hash模式&#xff0c;可以在in…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...