【QT5】<重点> QT网络编程

news2024/11/25 13:40:59

文章目录

前言

一、QT中的TCP编程

1. TCP简介

2. 服务端程序编写

3. 客户端程序编写

4. 服务端与客户端测试

二、QT中的UDP编程

1. UDP简介

2. UDP单播与广播程序


前言

本篇记录QT中TCP和UDP网络编程知识。


一、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_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    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和port
    QString 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_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    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_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

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

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

相关文章

关于事务流的思考

关于事务流的思考 1 事务流业务分析 ​ 不同业务可能有不同的审核流程&#xff0c;而activiti为大家提供了一套公用的审核功能&#xff0c;基于这些功能我们可以根据自己的业务需求组合出我们自己的审核流程&#xff0c;而这里我要实现的事务流有如下功能&#xff1a;角色为结…

MySQL 数据库 Navicat Premium 16.01 安装教程

MySQL 数据库 Navicat Premium 16.01 安装教程 目录 MySQL 数据库 Navicat Premium 16.01 安装教程前言安装步骤同意协议选择安装目录桌面快捷方式安装正在安装安装完成 步骤获取 前言 MySQL数据库管理用Navicat更加方便&#xff0c;可视化效果更好&#xff0c;今天给大家带来…

八股文之JVM

目录 1.JVM内存划分 2.JVM类加载过程 3.JVM垃圾回收机制GC 3.1.判断谁是垃圾 3.2.如何释放对应的内存 1.JVM内存划分 在一个Java程序运行起来之后&#xff0c;jvm就会从操作系统中申请一块内存&#xff0c;然后就会将该内存划分成多个部分&#xff0c;用于不同的用途。 …

python-03

使用File操作文件 open(file, moder, buffering-1,encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) file&#xff1a;要打开的文件 mode&#xff1a;文件打开模式。默认访问模式是读&#xff08;r&#xff09; buffering&#xff1a;缓冲区大小 encodin…

淘宝商品评论API接口测试实例(获取淘宝商品评论,翻页展示、支持并发)

item_review-获得淘宝商品评论 测试页 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop…

学生党蓝牙耳机性价比排行榜,好评榜TOP5机型推荐

随着科技的飞速发展&#xff0c;蓝牙耳机已经成为我们日常生活中不可或缺的一部分&#xff0c;无论是运动健身、通勤路上还是休闲娱乐&#xff0c;它都为我们带来了极大的便利&#xff0c;然而&#xff0c;市面上的蓝牙耳机种类繁多&#xff0c;价格参差不齐&#xff0c;如何选…

pg——psql命令行交互式客户端工具

1、启动数据库 ./pg_ctl -D /usr/local/pgsql/data/ -l /usr/local/pgsql/log 2、登录数据库 psql template1 3、查看所有数据库 \l 4、创建数据库 create database testdb; 5、连接某数据库 \c 数据库 6、查看数据下的表 \d 7、 查看数据库下的所有schema \dn 8、查看表的结构…

业务表对应主键为varChar类型且无自增策略的新增与修改问题

业务表对应主键为varChar类型且无自增策略的新增与修改问题 上周五领到一个需求&#xff0c;在开发过程中遇到一点小插曲&#xff0c;在此记录下&#xff0c;话不多说&#xff0c;直接看表结构&#xff1a; 这里机构id为主键且无自增策略&#xff0c;也就是说机构id这个字段是…

PHP安装配置

文章目录 1.下载PHP2.配置环境变量3.Apache安装配置 1.下载PHP PHP即“超文本预处理器”&#xff0c;是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言&#xff0c;与C语言类似&#xff0c;是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法…

Samba 服务器的搭建以及windows server 2008客户端的使用实验报告

一、 实验目的 通过 Samba 服务器的搭建&#xff0c;基本了解搭建服务器的基本步骤&#xff0c;理解 Samba 服务器的实现文件共享的功能&#xff0c;如何配置 Samba服务器配置文件等。 二、 实验环境 准备一台安装 centOS7系统的 Linux 虚拟机作为 Samba 服务器 server,准备…

海外仓系统有哪些?主流海外仓系统类型、优缺点,不同海外仓如何选择

作为海外仓的经营者&#xff0c;不管海外仓大小&#xff0c;你都应该知道海外仓系统对提升仓库管理效率有多重要。 不过现在市场上的海外仓系统确实种类太多了&#xff0c;想选到一个适合自己海外仓&#xff0c;性价比又比较高的wms海外仓系统也不是一件容易的事情。 本文会详…

GD32 MCU启动后如何运行到main函数

GD32 MCU启动后如何运行到main函数入口&#xff1f;你是否也有这样的疑虑。在执行到main函数之前MCU干了哪些事情呢&#xff1f;下面为大家解答。 MCMCU上电后&#xff0c;首先会根据BOOT0和BOOT1的状态判断从主Flash/SRAM/ISP中启动&#xff0c;如果BOOT0为低电平&#xff0c…

windows反弹shell的方法

什么是正向shell和反向shell 首先说&#xff0c;正向shell是控制端主动连接被控制端&#xff0c;通过目标主机开放一个监听端口等待其他主机访问&#xff0c;从而获得对目标主机的shell访问&#xff0c;优点是控制端可以整个控制目标主机&#xff0c;但缺点会受到防火墙的连&a…

多标签识别:JoyTag模型的图像标注革命【开源】

公共视觉模型通常会对其训练数据集进行严格过滤&#xff0c;这限制了这些基础模型在广泛概念上的表现&#xff0c;进而限制了表达自由、包容性和多样性。JoyTag通过结合Danbooru 2021数据集和一组手动标记的图像&#xff0c;努力提高模型对不同类型图像的泛化能力。 JoyTag项目…

简易版 | 代码生成器(包含插件)

一、代码生成器 先导入依赖 <!-- Mybatis-Plus --> <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.6</version> </dependency><!-- 代码生成器 --…

jvm必知必会-类的生命周期图文详解

类的生命周期描述了一个从加载、使用到卸载的过程; 而其中的 连接 部分又分为一下三个阶段: 验证准备解析6.1 加载阶段 Loading阶段第一步是 类加载器 会根据类全限定名通过不同的渠道以二进制流的方式获取字节码信息,程序员可以使用Java代码扩展不同的渠道。 比如通过 …

超强生图模型,抢先体验!

文生图模型Stable Diffusion 3 Medium开源啦&#xff01;优刻得GPU云主机目前已上线该模型镜像&#xff0c;开箱即用&#xff0c;即刻体验&#xff01;具体操作见文末。 近年来&#xff0c;生成式人工智能的快速发展正在改变我们的生活。作为这一领域的前沿技术之一&#xff0…

一个软件是如何开发出来的呢?

一、前言 如今&#xff0c;AI大爆发的时代&#xff0c;作为一名IT从业者&#xff0c;你是否也想尝试开发一套自己的系统&#xff0c;实现那些看似有可能实现的天马行空的想法&#xff0c;变成一个优秀甚至伟大的产品&#xff0c;甚至带来某个行业的革新&#xff0c;那作为一名…

rtthread stm32h743的使用(九)RT_WEAK报错

rtthread stm32h743的使用&#xff08;九&#xff09;RT_WEAK报错 我们要在rtthread studio 开发环境中建立stm32h743xih6芯片的工程。我们使用一块stm32h743及fpga的核心板完成相关实验&#xff0c;核心板如图&#xff1a; 我们新建工程&#xff0c;参考前面rtthread stm32h…

springboot 腾讯地图接口验签 java

1. 原因 需求需要通过小程序定位拿到用户所在行政区信息,但是小程序定位只能拿到经纬度信息,所以需要调用腾讯地图的逆地址解析(我认为:微信是腾讯的,那么使用腾讯地图的逆地址解析经度应该不会损失太多)如果WebServiceAPI Key配置中签名校验,那么调用接口就需要进行验签 2. W…