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

QT网络通信

九、网络

  1. 基础概念

1.1 TCP/UDP

TCP/UDP

UDP TCP 协议相同点:都存在于传输层,全双工通信

TCP:全双工通信、面向连接、可靠

TCP(即传输控制协议):是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。

高可靠原因:1.三次握手、四次挥手

2. 序列号和应答机制

3. 超时,错误重传机制

适用场景

适合于对传输质量要求较高的通信

在需要可靠数据传输的场合,通常使用TCP协议

MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议

UDP:全双工通信、面向无连接、不可靠

UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

适用场景

发送小尺寸数据(如对DNS服务器进行IP地址查询时)

适合于广播/组播式通信中。

MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议

1.2 IP地址与端口号

IP地址

1. IP地址是Internet中主机的标识,本质:  二进制

    IP地址一般分割为 4个八位二进制的数(4字节-32位)

2. Internet中的主机要与别的机器通信必须具有一个IP地址

3. IP地址(长度)为32位(IPv4),128位(IPv6),目前ipv6还未普及,主要学习ipv4

4. 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由 

5. 表示方法 :  点分十进制

  点分十进制表示就是用4组从0~255的数字,来表示一个IP地址。

端口号Port

1. 为了区分一台主机接收到的数据包应该给哪个进程来进行处理,使用端口号来区别

     (通过 IP地址 找到哪台主机  通过 port端口号 来找到哪台主机的哪个进程)

2. TCP端口号与UDP端口号独立 (UDP port为8888,TCP port也可为8888 )

3. 端口号一般由IANA (Internet Assigned Numbers Authority) 管理

4. 端口(sin_prot)用2个字节表示 2byte  (IP地址占4个字节)

众所周知端口(被占用): 1~1023(1~255之间为众所周知端口,通常由UNIX系统占用)

比如文件传输端口 TFTP  端口号为 69 

已登记端口:1024~49151   (----可用来建立与其它主机的会话----) 

动态或私有端口:49152~65535  --固定某些服务使用--

自定义的端口号建议使用2000以上,且非豹子号(例如6666/8888等)。

仅以使用2000以上,非豹子号的端口号,本次授课采用8887

2、准备工作

与数据库编程一样,Qt的网络功能需要在.pro项目配置文件中增加network模块。

网络编程主要用到两个类:

  • QTcpServer

表示一个基于Tcp的服务器,需要注意的是,此类直接继承了QObject类,不继承QIODevice类,因此不具备任何IO的能力。

  • QTcpSocket

表示一个基于TCP的Socket连接,间接继承了QIODevice类,因此使用此类对象进行IO读写。

3、相关函数

// 构造函数,堆内存开辟
QTcpServer::​QTcpServer(QObject * parent = 0)

// 开启监听服务,等待客户端发起连接
// 参数1:监听来源(那个网段的IP地址),默认值表示不加任何限制
// 参数2:服务器占用的端口号。默认值为0表示随机选取。8887
bool QTcpServer::​listen(const QHostAddress & address = QHostAddress::Any, quint16 port = 0)

// 查看当前是否正在监听
bool QTcpServer::​isListening() const

// 关闭监听服务
void QTcpServer::​close()

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    // 抢占前台
    setWindowFlags(Qt::WindowStaysOnTopHint);
    server = new QTcpServer(this);    // 开启监听
    bool result = server->listen(QHostAddress::Any,8887);
    if(!result)
    {
        ui->textBrowser->append("监听失败");
        return;
    }
    ui->textBrowser->append("监听开启成功,端口号为8887");
}Dialog::~Dialog()
{
    // 关闭监听功能
    if(server->isListening()) // 判断是否正在监听
    {
        server->close();
    }
    delete ui;
}

客户端

// 构造函数,堆区开辟
QTcpSocket::​QTcpSocket(QObject * parent = 0)

// 连接到服务器
// 参数1:服务器的IP地址
// 参数2:服务器的端口号
// 参数3:打开模式。默认读写模式
void QAbstractSocket::​connectToHost(const QString & hostName,
            quint16 port, 
            OpenMode openMode = ReadWritel)[virtual]

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    setWindowFlags(Qt::WindowStaysOnTopHint);    connect(ui->pushButtonConn,SIGNAL(clicked()),
            this,SLOT(btnConnClickedSlot()));
    connect(ui->pushButtonSend,SIGNAL(clicked()),
            this,SLOT(btnSendClickedSlot()));    socket = new QTcpSocket(this);
}Dialog::~Dialog()
{
    // 如果数据流处于打开状态
    if(socket->isOpen())
    {
        // 如果打开则关闭
        socket->close();
    }
    delete ui;
}void Dialog::btnConnClickedSlot()
{
    // 获取用户输入的IP和端口
    QString ip = ui->lineEditIp->text();
    int port = ui->spinBox->value();    // 建立连接
    socket->connectToHost(ip,port);
}void Dialog::btnSendClickedSlot()
{}

我们怎么直到,是否有客户端连接了那?

所有通知类,第一时间想到到的信号槽。

// 每当有新的连接可以用时,就会发出此信号
void QTcpServer::​newConnection() [signal]

// 连接成功的信号
void QAbstractSocket::​connected()[signal]

// 连接失败的信号
void QAbstractSocket::​disconnected()[signal]

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    setWindowFlags(Qt::WindowStaysOnTopHint);    connect(ui->pushButtonConn,SIGNAL(clicked()),
            this,SLOT(btnConnClickedSlot()));
    connect(ui->pushButtonSend,SIGNAL(clicked()),
            this,SLOT(btnSendClickedSlot()));    socket = new QTcpSocket(this);
    connect(socket,SIGNAL(connected()),
            this,SLOT(connectedSlot()));
    connect(socket,SIGNAL(disconnected()),
            this,SLOT(disconnectedSlot()));
}Dialog::~Dialog()
{
    // 如果数据流处于打开状态
    if(socket->isOpen())
    {
        // 如果打开则关闭
        socket->close();
    }
    delete ui;
}void Dialog::btnConnClickedSlot()
{
    // 获取用户输入的IP和端口
    QString ip = ui->lineEditIp->text();
    int port = ui->spinBox->value();    // 建立连接
    socket->connectToHost(ip,port);
}void Dialog::btnSendClickedSlot()
{}// 连接成功
void Dialog::connectedSlot()
{
    // 屏蔽连接按钮
    ui->pushButtonConn->setEnabled(false);
    ui->pushButtonConn->setText("已连接");    // 释放发送按钮
    ui->pushButtonSend->setEnabled(true);
}// 断开连接
void Dialog::disconnectedSlot()
{
    // 释放连接按钮
    ui->pushButtonConn->setEnabled(true);
    ui->pushButtonConn->setText("连接");    // 屏蔽发送按钮
    ui->pushButtonSend->setEnabled(false);
}

// 返回与客户端连接的QTcpSocket对象
QTcpSocket * QTcpServer::​nextPendingConnection()[virtual]

// 获取对面(客户端)的IP地址
// 返回值为IP地址封装类
QHostAddress QAbstractSocket::​peerAddress() const

// 返回对面的(客户端)端口号
quint16 QAbstractSocket::​peerPort() const

// 转换为IP地址字符串,在计算机中会自动增加一个前缀
QString QHostAddress::​toString() const

客户端.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    setWindowFlags(Qt::WindowStaysOnTopHint);    connect(ui->pushButtonConn,SIGNAL(clicked()),
            this,SLOT(btnConnClickedSlot()));
    connect(ui->pushButtonSend,SIGNAL(clicked()),
            this,SLOT(btnSendClickedSlot()));    socket = new QTcpSocket(this);
    connect(socket,SIGNAL(connected()),
            this,SLOT(connectedSlot()));
    connect(socket,SIGNAL(disconnected()),
            this,SLOT(disconnectedSlot()));
}Dialog::~Dialog()
{
    // 如果数据流处于打开状态
    if(socket->isOpen())
    {
        // 如果打开则关闭
        socket->close();
    }
    delete ui;
}void Dialog::btnConnClickedSlot()
{
    // 获取用户输入的IP和端口
    QString ip = ui->lineEditIp->text();
    int port = ui->spinBox->value();    // 建立连接
    socket->connectToHost(ip,port);
}void Dialog::btnSendClickedSlot()
{}// 连接成功
void Dialog::connectedSlot()
{
    // 屏蔽连接按钮
    ui->pushButtonConn->setEnabled(false);
    ui->pushButtonConn->setText("已连接");    // 释放发送按钮
    ui->pushButtonSend->setEnabled(true);
}// 断开连接
void Dialog::disconnectedSlot()
{
    // 释放连接按钮
    ui->pushButtonConn->setEnabled(true);
    ui->pushButtonConn->setText("连接");    // 屏蔽发送按钮
    ui->pushButtonSend->setEnabled(false);
}

服务端.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    // 抢占前台
    setWindowFlags(Qt::WindowStaysOnTopHint);
    server = new QTcpServer(this);    // 开启监听
    bool result = server->listen(QHostAddress::Any,8887);
    if(!result)
    {
        ui->textBrowser->append("监听失败");
        return;
    }
    ui->textBrowser->append("监听开启成功,端口号为8887");
    connect(server,SIGNAL(newConnection()),this,
            SLOT(newConnectionSlot()));
}Dialog::~Dialog()
{
    // 关闭监听功能
    if(server->isListening()) // 判断是否正在监听
    {
        server->close();
    }
    delete ui;
}void Dialog::newConnectionSlot()
{
    // 如果不是第一次连接,就踢掉上一个人
    if(socket != NULL)
    {
        // 踢掉上一个人
        socket->close();
    }    // 保存当前连接对象
    socket = server->nextPendingConnection();    // 获取对面的IP地址
    QString ip = socket->peerAddress().toString();    // 获取对面的端口号
    quint16 port = socket->peerPort();    ip.prepend("新连接来了!").append(":").append(QString::number(port));    ui->textBrowser->append(ip);
}

// 构造函数
// 参数事Qt的读写类,可以是QFile,也可以是QTcpSocket........
QTextStream::​QTextStream(QIODevice * device)

// 输出字符串内容,支持链式调用
QTextStream &	operator<<(const QString & string)

// 有数据可读时发射
void QIODevice::​readyRead()[signal]

// 读取最大长度为maxlen个QChar的内容,返回值为读取的字符串
QString QTextStream::​read(qint64 maxlen)

// 读取所有字符
QString QTextStream::​readAll()

// 一次读取一行文本
// 参数为一行文本的最大字符数
QString QTextStream::​readLine(qint64 maxlen = 0)

dialog.cpp 服务端

void Dialog::readyReadSlot()
{
    // 创建文本对象
    QTextStream input(socket);
    // 读取内容
    QString text = input.read(128);
    ui->textBrowser->append(text);
}

dialog.cpp 客户端

// 发送信息
void Dialog::btnSendClickedSlot()
{
    QString text = ui->lineEditSend->text();
    if(text == "")
    {
        QMessageBox::warning(this,"提示","请输入发送的内容");
        return;
    }    // 方法一:QTextStream 文本流
    // QTextStream直接使用Unicode编码,适合Qt与Qt之间通信。
    // 简化文本的读写操作
    QTextStream output(socket);
    // 发送数据
    output << text;
}

dialog.cpp 服务端

void Dialog::readyReadSlot()
{
//    // 创建文本对象
//    QTextStream input(socket);
//    // 读取内容
//    QString text = input.read(128);
//    ui->textBrowser->append(text);    // 读取所有内容
    QByteArray bufer = socket->readAll();
    // QByteArray -> QString
    QString text(bufer);
    // 显示
    ui->textBrowser->append(text);
}

dialog.cpp 客户端

void Dialog::btnSendClickedSlot()
{
    QString text = ui->lineEditSend->text();
    if(text == "")
    {
        QMessageBox::warning(this,"提示","请输入发送的内容");
        return;
    }    // 方法一:QTextStream 文本流
    // QTextStream直接使用Unicode编码,适合Qt与Qt之间通信。
    // 简化文本的读写操作
//    QTextStream output(socket);
//    // 发送数据
//    output << text;    // 方法二、QByteArray
    // 以字节为单位,可以与其他编程语言通信
    // 可以操作非文本内容
    // QString -> QByteArray
    QByteArray buffer = text.toUtf8();
    socket->write(buffer);
}

相关文章:

QT网络通信

九、网络 基础概念 1.1 TCP/UDP TCP/UDP UDP TCP 协议相同点&#xff1a;都存在于传输层&#xff0c;全双工通信 TCP&#xff1a;全双工通信、面向连接、可靠 TCP&#xff08;即传输控制协议&#xff09;&#xff1a;是一种面向连接的传输层协议&#xff0c;它能提供高可靠性通…...

案例分析|山西某光伏发电站轨道巡检机器人解决方案

随着光伏发电技术的不断发展&#xff0c;光伏变电站配电室作为能量转换和输送的关键节点&#xff0c;承担着重要的电力分配和保护功能。然而&#xff0c;传统的人工巡检方式存在诸多问题&#xff0c;如巡检周期长、效率低、安全风险高等&#xff0c;已经无法满足光伏变电站配电…...

Apache POl

介绍 Apache POl是一个处理Miscrosoft Ofice各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作,一般情况下&#xff0c;POI都是用于操作 Excel 文件。 Apache POl 的应用场景 1.银行网银系统导出交易…...

高防服务器托管应注意什么

选择高防服务器托管主要考虑的因素&#xff1a;1.服务商的服务器大小。2.服务器的防御值大小。3.服务器机房的位置以及机房的资质。 具体内容如下&#xff1a; 1&#xff0e;服务器大小是按照U来定的&#xff0c;U是一种表示服务器外部尺寸的单位(计量单位&#xff1a;高度或厚…...

swagger-ui.html报错404,解决办法

swagger-ui.html报错404,解决办法&#xff01;现在后端开发项目中&#xff0c;为了节省时间&#xff0c;使用swagger插件&#xff0c;可以方便的快捷生成接口文档。但是如果你在请求前端页面路径比如&#xff1a;http://127.0.0.1:7777/swagger-ui.html。找不到。那是因为你的配…...

golang 函数式编程库samber/mo使用: Future

golang 函数式编程库samber/mo使用&#xff1a; Future 如果您对samber/mo库不了解&#xff0c; 请先阅读第一篇 Option 本节讲述Future的使用&#xff0c;它可以帮助我们处理异步编程问题。 示例 我们先来看看下面代码的示例&#xff0c; 注释解释了每一步的操作。 packa…...

【Spring连载】使用Spring Data访问 MongoDB(十四)----Mongodb特有的查询方法

【Spring连载】使用Spring Data访问 MongoDB&#xff08;十四&#xff09;----Mongodb特有的查询方法 一、定义通用查询方法二、MongoDB特有的查询方法2.1 地理空间查询Geo-spatial Queries2.2 基于JSON的查询方法和字段限制2.3 使用SpEL表达式的基于JSON的查询2.4 全文检索查询…...

消息中间件篇之RabbitMQ-消息重复消费

一、导致重复消费的情况 1. 网络抖动。 2. 消费者挂了。 消费者消费消息后&#xff0c;当确认消息还没有发送到MQ时&#xff0c;就发生网络抖动或者消费者宕机。那当消费者恢复后&#xff0c;由于MQ没有收到消息&#xff0c;而且消费者有重试机制&#xff0c;消费者就会再一次消…...

常见设计模式之单例模式

单例模式 单例模式是一种常用的软件设计模式&#xff0c;主要目的是确保一个类在整个应用程序生命周期中只有一个实例&#xff0c;并提供一个全局访问点以获取该实例。 单例模式分为几种不同的实现方式&#xff0c;包括懒汉模式和饿汉模式。每种方式都有其特点和适用场景。例如…...

VL817-Q7 USB3.0 HUB芯片 适用于扩展坞 工控机 显示器

VL817-Q7 USB3.1 GEN1 HUB芯片 VL817-Q7 USB3.1 GEN1 HUB芯片 VIA Lab的VL817是一款现代USB 3.1 Gen 1集线器控制器&#xff0c;具有优化的成本结构和完全符合USB标准3.1 Gen 1规范&#xff0c;包括ecn和2017年1月的合规性测试更新。VL817提供双端口和双端口4端口配置&…...

【Android安全】Windows 环境下载 AOSP 源码

准备环境 安装 git 安装 Python 硬盘剩余容量最好大于 800G 打开 Git Bash&#xff0c;用 git 克隆源代码仓库 git clone https://android.googlesource.com/platform/manifest.git //没有梯子使用清华源 git clone https://aosp.tuna.tsinghua.edu.cn/platform/manifest.git这…...

Vue.js+SpringBoot开发快递管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 数据中心模块2.2 快递类型模块2.3 快递区域模块2.4 快递货架模块2.5 快递档案模块 三、界面展示3.1 登录注册3.2 快递类型3.3 快递区域3.4 快递货架3.5 快递档案3.6 系统基础模块 四、免责说明 一、摘要 1.1 项目介绍 …...

Linux/Spectra

Enumeration nmap 第一次扫描发现系统对外开放了22&#xff0c;80和3306端口&#xff0c;端口详细信息如下 22端口运行着ssh&#xff0c;80端口还是http&#xff0c;不过不同的是打开了mysql的3306端口 TCP/80 进入首页&#xff0c;点击链接时&#xff0c;提示域名不能解析&…...

C 嵌入式系统设计模式 08:硬件代理模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之一&…...

【k8s配置与存储--持久化存储(PV、PVC、存储类)】

1、PV与PVC 介绍 持久卷&#xff08;PersistentVolume&#xff0c;PV&#xff09; 是集群中的一块存储&#xff0c;可以由管理员事先制备&#xff0c; 或者使用存储类&#xff08;Storage Class&#xff09;来动态制备。 持久卷是集群资源&#xff0c;就像节点也是集群资源一样…...

【Vite】解决Vite http proxy error: Error: connect ECONNREFUSED

今天写bug&#xff0c;发现了这个问题 我经过我一晚上的搜索努力&#xff0c;在github上找到了解决办法&#xff0c;不得不说&#xff0c;交友网站还是很好用的。 参考 这一行是关键代码。 因为我连的是本地后台服务&#xff0c;所以最后配置成这样 server: {open: true,pro…...

FPGA领域顶级学术会议

FPGA领域顶级学术会议主要有FPGA,FCCM,FPL和FPT。 1 FPGA 会议全名是: ACM/SIGDA International Symposium on Field-Programmable Gate Arrays 网站是:https://dl.acm.org/conference/fpga FPGA常年在美国举办,每年2月,偏FPGA基础研究; 该会议的论文免费下载。这个比…...

罗技鼠标滚轮模式介绍 | 鼠标滚轮异响 - 解决方案

滚轮模式介绍 针对罗技的滚轮模式进行介绍&#xff1a; 普通滚轮&#xff1a;滚动时有明显段落感&#xff0c;无法快速滚动。 智能滚轮&#xff1a;滚动力量较弱时&#xff0c;与普通滚轮无异&#xff1b;滚动力量大时&#xff0c;鼠标会自动减小滚轮阻尼&#xff0c;从而使滚…...

Scrapy与分布式开发(2.2):正则表达式

使用Python的re模块进行正则表达式操作详细讲解 一、引言 正则表达式是一种强大的文本处理工具,它使用特定的模式来搜索、匹配和替换文本。Python的re模块(正则表达式模块)提供了正则表达式匹配操作的所有功能。下面我们将详细讲解如何使用re模块进行正则表达式的操作。 …...

今年“全国爱耳日”主题确定!立聪堂助听器组织社区义诊

2024年3月3日是第二十五个“全国爱耳日”。 今年的活动主题定为“科技助听&#xff0c;共享美好生活”&#xff0c;旨在倡导全社会关注听力健康&#xff0c;并鼓励听力受损人群利用科技手段实现早期康复。 为响应这一主题&#xff0c;知名助听器验配连锁机构立聪堂迅速行动起…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...