跳转到内容

网络协议软件手册

1.HTTP/HTTPS

1.1. HTTP/HTTPS 概述

HTTP(Hyper Text Transfer Protocol,超文本传输协议)是互联网上使用最广泛的网络协议。它是客户端与服务器之间请求和响应的标准,也是用于将超文本从 WWW 服务器传输到本地的通信协议。

另一方面,HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer)是以安全为目的的 HTTP 通道,它在传统 HTTP 的基础上对通信进行加密和身份认证(增加 SSL/TLS 安全协议),从而保证通信过程中的安全性。

1.1.1 HTTP 与 HTTPS 的区别

HTTP 与 HTTPS 的区别如下表所示。

协议HTTPHTTPS
CA 证书不需要需要
通信加密方式明文通信,不加密SSL/TLS 加密通信
连接方式使用端口号 80使用端口号 443
连接状态无状态基于 SSL+HTTP 协议构建,可进行加密通信和身份认证的网络协议

1.1.2 请求与响应

典型的 HTTP/HTTPS 通信发生在浏览器与 Web 服务器之间。浏览器作为“客户端”,负责发送请求、接收消息以及渲染显示;Web 服务器作为“服务器”,负责响应请求、管理服务器文件以及处理具体业务。在特定情况下,HTTP 也可以作为信息交换的通信规则。

客户端在需要资源时发送的内容称为“请求消息(Request)”,服务器接收到请求后返回给客户端的内容称为“响应消息(Response)”。HTTP 规定了这些请求消息和响应消息的格式。

请求消息格式

请求消息格式

请求消息的格式如下。

消息元素说明
请求行 (Request Line)请求方法:常见方法如下。

・GET:用于查询和获取服务器资源。请求内容会显示在 URL 上。

・POST:用于在服务器上创建或更新内容。请求内容不会显示在 URL 上,而是包含在消息体中。

URL:服务器的虚拟文件路径。详细内容将在下一节说明。

响应消息的主要组成部分如下。

  • 状态行:包含协议版本、状态码和状态短语。

  • 响应头:以键值对形式存在(例如日期时间、数据类型、数据长度等)。

  • 空行:用于区分头部和正文的空行。

  • 响应正文:如果是网页,通常为 HTML 代码,也可能是音频、视频文件或图片。通常由头部中的 Content-Type 指定。

响应消息格式

响应消息格式

1.1.3 URL

假设构建了一个环境监测服务器系统,用于采集并记录市内各观测点的环境数据。假设公共网络上的域名为 www.huanjin.com,服务器内有两台设备,每台设备都保存了不同日期的气温数据。当客户端调用某台设备的某条特定数据时,需要向服务器发送一个唯一路径以便服务器检索。这个唯一路径就是 URL

环境监测服务器的 URL 结构示例

环境监测服务器的 URL 结构示例

URL(Uniform Resource Locator,统一资源定位符)位于请求消息的请求行中,起到路标作用。浏览网页并点击各种组件时,浏览器会自动补全不同的 URL。完整 URL 由协议部分URL(域名)部分文件地址组成。

URL 组成元素示例

URL 组成元素示例

具体内容如下。

组成部分说明
协议由 // 分隔。常见协议有 http 和 https。
URL(域名)公共网络上的唯一域名。
文件地址域名后第一个 / 到最后一个 / 之前的内容称为“虚拟目录”。

最后一个 / 之后到 # 之前的内容为“文件名”。

例如,如果想获取环境监测服务器中“设备 1”的“12 月 25 日”数据,则使用 GET 请求,URL 类似于 http://www.huanjin.com/Device-1/日付データ/20211225

URL 中也可以包含变量信息(URL 查询字符串)。格式如下。

Terminal window
https://www.Adblock.com/s?a=123&b=234

变量位于 URL 末尾,以 ? 开头,并以 参数名=值 的键值对形式保存。多个参数之间用 & 分隔。

1.1.4 HTTPS 使用要点

根据上述说明,使用 HTTPS 时需要始终注意以下几点。

  • CA 证书:HTTPS 协议使用 SSL/TLS。

  • 数据发送:使用 POST 请求,服务器地址以 URL 形式表示。

  • 数据/文件接收:使用 GET 请求,服务器地址以 URL 形式表示。

我们的 easyeai-api 软件开源库统一封装了复杂的消息格式和收发操作,使用户可以通过简单便捷的调用方式实现 HTTP/HTTPS 通信功能。

1.2. 快速开始

1.2.1 开发环境准备

如果是第一次阅读本文档,请先阅读《入门指南/开发环境准备/Easy-Eai 编译环境的准备与更新》,并按照其中步骤搭建编译环境。

在 PC 上的 Ubuntu 系统中运行 run 脚本,进入 EASY-EAI 编译环境。具体如下。

Terminal window
cd ~/develop_environment
./run.sh 2204

1.2.2 下载源码并编译示例

在 EASY-EAI 编译环境下,创建用于管理源码仓库的目录。

Terminal window
cd /opt
mkdir EASY-EAI-Toolkit
cd EASY-EAI-Toolkit

https://dl.dragonwake.com/download/rv1126b/embedded/EASY-EAI-Toolkit-1126B/Demos.zip

从上述链接下载 Demos.zip 压缩文件,上传到虚拟机的 /opt/EASY-EAI-Toolkit 目录并解压。 进入对应示例目录并执行编译操作。具体命令如下。

Terminal window
cd EASY-EAI-Toolkit-1126B/Demos/netProtocol-http/
./build.sh

💡 注意:由于依赖库放置在板端,交叉编译过程中必须保持 /mnt 挂载。

HTTP 示例构建结果

HTTP 示例构建结果

1.2.3 运行示例

通过串口调试或 SSH 调试进入板端后台,并切换到示例所在位置,如下所示。

Terminal window
cd /userdata/Demo/netProtocol-http

HTTP 示例目录

HTTP 示例目录

运行示例的命令如下。

Terminal window
./test-http_server & ./test-http_client

1.2.4 运行结果

运行结果如下。

HTTP 示例运行结果

HTTP 示例运行结果

1.3. HTTPS 库函数说明

本章说明 EASY EAI 的 HTTPS 库函数使用方法。

1.3.1 包含/引用方法

EASY EAI api 库位于本仓库的 easyeai-api 目录中。为了方便用户在本地项目中直接调用 EASY EAI api 库,下面列出了项目中需要链接的库、头文件等。

说明CMake 中的写法Makefile 中的写法
api.cmake${netProtocol_root}/http/api.cmake
头文件目录${HTTP_INCLUDE_DIRS}-I ../../easyeai-api/netProtocol/http
源码文件目录${HTTP_SOURCE_DIRS}../../easyeai-api/netProtocol/http
库文件目录
库链接参数${HTTP_LIBS}

API 源码路径为 EASY-EAI-Toolkit-1126B/easyeai-api/netProtocol/http/。用户可以通过源码查看接口实现,也可以直接修改源码。

1.3.2 证书设置

设置证书的函数原型如下。

Terminal window
void set_customer_crt(const char \*crt_file);

具体说明如下。

函数名:set_customer_crt()详细信息
头文件easyeai-api/netProtocol/http/https_request.h
输入参数crt_file:证书路径
返回值
注意事项

1.3.3 向 HTTP/HTTPS 服务器发送 form-data 数据

1.3.3.1 清除 form_data 缓存

清除缓存的函数原型如下。

Terminal window
void clear_multipart();

具体说明如下。

函数名:clear_multipart()详细信息
头文件easyeai-api/netProtocol/http/https_request.h
输入参数
返回值
注意事项form-data 缓存只有一个,因此无论在哪里执行,form-data 缓存都会被清空。如果在多线程中执行该函数,请注意线程同步问题。

1.3.3.2 添加 form_data 缓存(填充)

添加缓存的函数原型如下。要发送的数据以键值对形式添加。

Terminal window
void add_multipart_form_data(const char \*key, const char \*value);

具体说明如下。

函数名:add_multipart_form_data()详细信息
头文件easyeai-api/netProtocol/http/https_request.h
输入参数key:form-data 数据的键名

value:form-data 数据内容
返回值
注意事项form-data 缓存只有一个。执行 clear_multipart() 后,此前添加到缓存中的所有 form-data 数据都会被清除。如果在多线程中执行,请注意线程同步问题。

1.3.3.3 发送 form-data 数据

HTTP 与 HTTPS 的加密方式不同,因此虽然参数相同,但定义了两个函数。函数原型如下。

Terminal window
int32_t send_data_to_Http(const char *server, const char *func, char *result, uint32_t result_lenth);
int32_t send_data_to_Https(const char *server, const char *func, char *result, uint32_t result_lenth);

具体说明如下。

HTTP 发送函数:send_data_to_Http()
HTTPS 发送函数:send_data_to_Https()
详细信息
头文件easyeai-api/netProtocol/https/https_request.h(按原文保留)
输入参数server:服务器 URL

func:方法(路径/API 名)

result:用于保存 HTTP/HTTPS 返回正文数据的缓冲区

result_lenth:用户为正文数据分配的缓冲区最大大小
返回值-1:失败

0:成功。函数内部会自动调用 clear_multipart() 并清除缓存。
注意事项该接口封装了 HTTP/HTTPS POST 请求,用于发送 form-data 缓存。调用成功后会清除缓存。在多线程环境中请注意同步。

1.3.4 向 HTTP/HTTPS 服务器发送 JSON 数据

由于 HTTP 与 HTTPS 的加密方式不同,因此分别定义了函数(参数相同)。

Terminal window
int32_t send_json_to_Http(const char *server, const char *func, const char *json, char *result, uint32_t result_length);
int32_t send_json_to_Https(const char *server, const char *func, const char *json, char *result, uint32_t result_length);

具体说明如下。

HTTP 发送函数:send_json_to_Http()
HTTPS 发送函数:send_json_to_Https()
详细信息
头文件easyeai-api/netProtocol/https/https_request.h
输入参数server:服务器 URL

func:方法(路径/API 名)

json:要发送的 JSON 字符串

result:用于保存返回正文数据的缓冲区

result_lenth:用户为正文数据分配的缓冲区最大大小
返回值-1:失败

0:成功
注意事项

1.3.5 从 HTTP/HTTPS 服务器获取文件

由于 HTTP 与 HTTPS 的加密方式不同,因此分别定义了函数(参数相同)。

Terminal window
int32_t get_file_from_https(const char *url, const char *func, const char *filePath);
int32_t get_file_from_http(const char *url, const char *func, const char *filePath);

具体说明如下。

HTTP 文件获取函数:get_file_from_https()(按原文保留)
HTTPS 文件获取函数:get_file_from_http()(按原文保留)
详细信息
头文件easyeai-api/netProtocol/https/https_request.h
输入参数url:服务器 URL 路径

func:方法(路径)

filePath:保存所获取文件的本地路径
返回值Success、Unknown、Connection、BindIPAddress、ReadWrite、ExceedRedirectCount、Canceled、SSLConnection、SSLLoadingCerts、SSLServerVerification、UnsupportedMultipartBoundaryChars、Compression 等
注意事项该接口封装了 HTTP/HTTPS GET 请求。

1.4. 使用示例

示例代码路径为 EASY-EAI-Toolkit-1126B/Demos/netProtocol-http/test-http_client.c。

1.4.1 设置 CRT 密钥文件(证书)

密钥文件设置操作如下。

Terminal window
set_customer_crt("/userdata/customer.crt");

1.4.2 发送 form_data 数据

1.4.2.1 添加数据

清除 form_data 数据缓冲区,然后向 form_data 缓冲区中添加数据。

Terminal window
clear_multipart();
add_multipart_form_data("name", "gzlmo");
add_multipart_form_data("id", "888888");
add_multipart_form_data("pwd", "123456");

1.4.2.2 发送数据

发送操作如下。

Terminal window
send_data_to_Http("192.168.3.191:50000", "/add", res, sizeof(res));

1.4.3 发送 JSON 数据

JSON 数据发送操作如下。

Terminal window
send_json_to_Http("192.168.3.191:50000", "/add", "{name : \\gzlmo\\}", res, sizeof(res));

2.MQTT

2.1. MQTT 概述

MQTT(Message Queuing Telemetry Transport)是一种基于发布/订阅(publish/subscribe)模型的“轻量级”通信协议。MQTT 最大的优点是能够以极少的代码和有限的带宽,为远程设备连接提供实时且可靠的消息服务。作为开销小、带宽消耗低的即时通信协议,它被广泛应用于 IoT(物联网)、小型设备、移动应用等领域。

2.1.1 发布与订阅

MQTT 采用的发布/订阅消息模型提供了一对多的消息分发机制,实现了应用之间的松耦合。在这种消息传递模型中,消息并不是从发送方直接发送到接收方(点对点),而是通过 MQTT 服务器(也称 MQTT Broker)进行分发。

  • MQTT 通信过程中存在三个角色:发布者(Publisher)代理/服务器(Broker)、订阅者(Subscriber)。

  • MQTT 传输的消息分为主题(Topic)和载荷(Payload)两个部分。

MQTT 发布/订阅模型

MQTT 发布/订阅模型

发布者向 Broker(MQTT Broker)发布特定主题的消息,Broker 会将该消息推送给所有订阅该主题的订阅者。

  • 发布消息的客户端是发布者,订阅主题消息的客户端是订阅者。

2.1.2 服务质量(QoS: Quality of Service levels)

服务质量是 MQTT 的重要特性之一。使用 TCP/IP 时,连接在一定程度上受到保护。但在无线网络中,断开和干扰经常发生,因此 MQTT 的 QoS 等级有助于防止信息丢失。

2.1.2.1 QoS 0

“最多一次(At most once)”。消息投递完全依赖底层 TCP/IP 网络。消息可能丢失或重复。该等级适用于环境传感器数据等场景,因为后续数据会很快发送,偶尔漏掉一条记录不会造成问题。

MQTT QoS 0 通信流程

MQTT QoS 0 通信流程

2.1.2.2 QoS 1

“至少一次(At least once)”。保证消息到达,但消息可能重复到达。

MQTT QoS 1 通信流程

MQTT QoS 1 通信流程

2.1.2.3 QoS 2

“恰好一次(Exactly once)”。保证消息只到达一次。该等级适用于计费系统等场景,因为消息重复或丢失都会导致错误结果。

MQTT QoS 2 通信流程

MQTT QoS 2 通信流程

  • 带有唯一消息 ID 的消息会同时保存在发送方和接收方。QoS 2 级别在发送方和接收方都需要两个流程,因此网络开销最高。

2.1.3 开源项目介绍

Eclipse Paho C 库使用广泛且社区活跃,是目前最常见、最受欢迎的 C 语言 MQTT 客户端开源库。它适用于 Windows、macOS、Linux、FreeRTOS、ESP32 等平台。

在 Ubuntu 系统中,可以直接编译 GitHub 仓库以获取所需库和头文件,也可以使用以下命令直接安装(此步骤可选):

Terminal window
sudo apt-get update
sudo apt-get install libpaho-mqtt-dev

Paho C 的优点是支持平台丰富、兼容性高,但也存在 API 偏底层、使用不便、还需要自行进行封装处理的限制。

因此,本文档采用 Eclipse 旗下的另一个 MQTT 项目 mosquitto。该项目更适合资源受限的嵌入式设备,虽然不如 Paho C 全面,但能满足基本需求,并且非常易用。

在 Ubuntu 系统中,可使用以下命令直接安装相关开发库:

Terminal window
sudo apt-get update
sudo apt-get install libmosquitto-dev

2.1.4 常见通信模型

常见用法是将 MQTT Server(Broker)程序部署到云端,板卡(开发板)作为发布者和订阅者进行数据收发通信。

MQTT 通信模型

MQTT 通信模型

如果要在局域网(LAN)内使用,也可以在 PC 平台(Windows/Linux)上部署 MQTT Server,让板卡作为发布者和订阅者进行通信。

例如,可在 Ubuntu 系统中执行以下命令部署 MQTT Server:

Terminal window
sudo apt-get update
sudo apt-get install mosquitto
sudo systemctl start mosquitto

如果希望 MQTT Server 在 Ubuntu 启动时自动启动,请额外执行以下命令:

Terminal window
sudo systemctl enable mosquitto

2.1.5 Demo 说明

为了便于说明 Demo,本文档将 Broker、Subscriber、Publisher 全部部署在同一块板卡设备上。

首先给板卡上电并连接网络。然后通过串口或 SSH 进入板端后台,安装 MQTT 相关资源:

Terminal window
sudo apt-get update
sudo apt-get install libmosquitto-dev mosquitto
sudo systemctl enable mosquitto && sudo systemctl start mosquitto

2.2. 快速开始

2.2.1 开发环境准备

如果是第一次阅读本文档,请先阅读《入门指南/开发环境准备/Easy-Eai 编译环境的准备与更新》,并按照其中步骤搭建编译环境。

在 PC 上的 Ubuntu 系统中运行 run 脚本,进入 EASY-EAI 编译环境。

Terminal window
cd ~/develop_environment
./run.sh 2204

2.2.2 下载源码并编译示例

在 EASY-EAI 编译环境下,创建用于管理源码仓库的目录。

Terminal window
cd /opt
mkdir EASY-EAI-Toolkit
cd EASY-EAI-Toolkit

https://dl.dragonwake.com/download/rv1126b/embedded/EASY-EAI-Toolkit-1126B/Demos.zip 从上述链接下载 Demos.zip 压缩文件,上传到虚拟机的 /opt/EASY-EAI-Toolkit 目录并解压。 进入对应示例目录并执行编译操作。

Terminal window
cd EASY-EAI-Toolkit-1126B/Demos/netProtocol-mqtt/
./build.sh

MQTT 示例构建结果

MQTT 示例构建结果

💡 注意:由于依赖库放置在板端,交叉编译过程中必须保持 /mnt 挂载。如果编译失败并出现找不到 mosquitto.h 的错误,请查看 1.5 Demo 说明 小节。

2.2.3 运行示例

通过串口调试或 SSH 进入板端后台,切换到示例程序所在位置。

Terminal window
cd /userdata/Demo/netProtocol-mqtt

MQTT 示例目录

MQTT 示例目录

首先运行 Subscriber 程序:

Terminal window
./test-mqtt_subscription &

MQTT Subscriber 启动结果

MQTT Subscriber 启动结果

💡 注意:如果执行失败并显示“Connection refused(连接被拒绝)”,请查看 1.5 Demo 说明 小节。Subscriber 会在后台运行,因此再次运行前请先使用 kill 命令结束进程。

接着运行 Publisher 程序:

Terminal window
./test-mqtt_publish

2.2.4 実行結果

从运行结果可以看到,Subscriber 正常接收并输出了 Publisher 发送的消息。

MQTT 收发运行结果

MQTT 收发运行结果

2.3. Mosquitto 库函数说明

本章说明本示例使用的 mosquitto 库接口。更详细的 API 说明请参阅官方网站 API 文档(https://mosquitto.org/api/files/mosquitto-h.html)。

2.3.1 引用方法

EASY EAI api 库位于本仓库的 easyeai-api 目录中。项目中需要链接的库、头文件等如下。

说明CMake 中的写法Makefile 中的写法
api.cmake${netProtocol_root}/mqtt/api.cmake
头文件目录${MQTT_INCLUDE_DIRS}$SYSROOT/usr/include/
源码文件目录${MQTT_SOURCE_DIRS}
库文件目录$SYSROOT/usr/lib/aarch64-linux-gnu/
库链接参数${MQTT_LIBS}-lmosquitto -lcrypto -lssl -lstdc++

API 源码路径为 EASY-EAI-Toolkit-1126B/easyeai-api/netProtocol/mqtt/。

2.3.2 初始化 Mosquitto 库

Terminal window
int mosquitto_lib_init(void);
项目详细信息
函数名mosquitto_lib_init()
头文件$SYSROOT/usr/include/mosquitto.h
输入参数
返回值MOSQ_ERR_SUCCESS (0):初始化成功

2.3.3 新建 Mosquitto 客户端实例

Terminal window
struct mosquitto \*mosquitto_new(const char \*id, bool clean_session, void \*userdata);
项目详细信息
函数名mosquitto_new(const char *id, bool clean_session, void *userdata)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数id:客户端标识符(字符串)

clean_session:为 true 时,断开连接时清除会话信息;为 false 时,保留会话信息。

userdata:指向用户自定义数据的指针
返回值struct mosquitto *(指向实例的指针)

2.3.4 设置连接回调函数

处理与 Broker 的连接状态变化。

Terminal window
void mosquitto_connect_callback_set(struct mosquitto \*mosq, void (\*on_connect)(struct mosquitto \*, void \*,int));
项目详细信息
函数名mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int))
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

on_connect:指向连接回调函数的指针(返回值 void,参数:客户端实例、用户数据、连接返回码)

2.3.5 设置断开连接回调函数

处理与 Broker 断开连接的事件。

Terminal window
void mosquitto_disconnect_callback_set(struct mosquitto \*mosq, void (\*on_disconnect)(struct mosquitto \*, void \*, int));
项目详细信息
函数名mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int))
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

on_disconnect:指向断开连接回调函数的指针(返回值 void,参数:客户端实例、用户数据、断开连接返回码)

2.3.6 设置消息发布回调函数

处理消息成功发送到 Broker 时的事件。

Terminal window
void mosquitto_publish_callback_set(struct mosquitto \*mosq, void (\*on_publish)(struct mosquitto \*, void \*, int));
项目详细信息
函数名mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int))
头文件netProtocol-mqtt/include/mosquitto.h
输入参数mosq:客户端实例

on_publish:指向消息发布回调函数的指针(参数:客户端实例、用户数据、消息 ID)

2.3.7 设置订阅回调函数

处理主题订阅成功时的事件。

Terminal window
void mosquitto_subscribe_callback_set(struct mosquitto \*mosq, void (\*on_subscribe)(struct mosquitto \*, void \*, int, int, const int \*));
项目详细信息
函数名mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *))
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

on_subscribe:回调函数指针。参数依次为:客户端实例、用户数据指针、消息 ID、成功的主题数量、QoS 等级数组。

2.3.8 连接到指定 Broker

Terminal window
int mosquitto_connect(struct mosquitto \*mosq, const char \*host, int port, int keepalive);
项目详细信息
函数名mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

host:Broker 地址

port:Broker 端口号

keepalive:保活时间(秒)

2.3.9 订阅主题

Terminal window
int mosquitto_subscribe(struct mosquitto \*mosq, int \*mid, const char \*sub, int qos);
项目详细信息
函数名mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

mid:指向存储消息 ID 的变量的指针(也可为 NULL)

sub:要订阅的主题字符串

qos:订阅的 QoS 等级
返回值MOSQ_ERR_SUCCESS 表示成功,其他值表示失败

2.3.10 向指定主题发布消息

Terminal window
int mosquitto_publish(struct mosquitto \*mosq, int \*mid, const char \*topic, int payloadlen, const void \*payload, int qos, bool retain);
项目详细信息
函数名mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

mid:用于存储消息 ID 的指针(也可为 NULL)

topic:发布目标主题字符串

payloadlen:消息载荷长度

payload:指向消息载荷数据的指针

qos:QoS 等级

retain:为 true 时保留(Retain)消息
返回值MOSQ_ERR_SUCCESS 表示成功,其他值表示失败

2.3.11 从 Broker 断开连接

Terminal window
void mosquitto_destroy(struct mosquitto \*mosq);
項目詳細
函数名mosquitto_disconnect(struct mosquitto *mosq)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

2.3.12 销毁 Mosquitto 客户端实例

Terminal window
void mosquitto_destroy(struct mosquitto \*mosq);
項目詳細
函数名mosquitto_destroy(struct mosquitto *mosq)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数mosq:客户端实例

2.3.13 清理 Mosquitto 库使用的资源

Terminal window
void mosquitto_lib_cleanup(void);
项目详细信息
函数名mosquitto_lib_cleanup(void)
头文件$SYSROOT/usr/include/mosquitto.h
输入参数

2.4. 使用示例

  • 发送(Publish)示例代码路径:

EASY-EAI-Toolkit-1126B/Demos/netProtocol-mqtt/test-mqtt_publish.c

  • 订阅(Subscribe)示例代码路径:

EASY-EAI-Toolkit-1126B/Demos/netProtocol-mqtt/test-mqtt_subscription.c

3.MODBUS

3.1. MODBUS 概述

MODBUS 是一种应用层消息传输协议,用于在通过不同类型总线或网络连接的设备之间进行客户端/服务器通信。Modbus 比其他通信协议使用更广泛的主要原因是:它公开发布且没有版权要求,易于部署和维护,并且对于供应商在移动本地位和字节时限制较少。

3.1.1 协议版本与内容

目前,Modbus 协议存在支持串口、以太网以及其他互联网协议的网络版本。

大多数 Modbus 设备通过串行 EIA-485 物理层进行通信。串行连接有两种变体,它们在数值数据表示方式和协议细节上略有不同。MODBUS 模式分为三类:RTU(远程终端单元)模式、ASCII(美国信息交换标准代码)模式,以及 TCP(运行在以太网上的协议)模式。

  • Modbus RTU:一种以二进制表示数据的紧凑方式(Modbus 协议规定默认模式必须为 RTU,ASCII 为可选)。

  • Modbus ASCII:一种人类可读的冗长表示方式。

这两种变体都使用串行通信(serial communication)。通过 TCP/IP(如以太网)连接时,存在多种 Modbus/TCP 变体,该方式不需要计算校验和。这三种通信协议在数据模型和函数调用方面完全相同,仅封装方式不同。

3.1.2 通信与设备

Modbus 协议采用主/从(master/slave)架构。一个节点为主节点,其他使用 Modbus 协议参与通信的节点为从节点。每个从设备都有唯一地址。在串行网络和 MB+ 网络中,只有被指定为主节点的节点才能发起命令(在以太网上,任何设备都可以发送 Modbus 命令,但通常只有一个主节点设备发起命令)。

Modbus 命令中包含要执行该命令的设备的 Modbus 地址。所有设备都会接收命令,但只有指定地址的设备会执行命令并响应(地址 0 是例外,指定地址 0 的命令为广播命令,所有接收到命令的设备都会执行,但不会响应)。所有 Modbus 命令都包含校验码,用于确认到达的命令没有损坏。基本 Modbus 命令可以让 RTU 修改其寄存器中的某个特定值、控制或读取 I/O 端口,或指示设备返回其寄存器中的一个或多个数据。

3.1.3 MODBUS 使用要点

根据以上说明,使用 Modbus 时需要始终注意以下几点。

  • Modbus 是主从方式通信,不能异步通信。

  • 如果主站不发送,总线上就不会发生数据通信。

  • 设备必须支持 RTU 协议(这是 Modbus 协议中的规定)。

  • 基本流程如下。

    • 发送:从站地址 + 功能码 + 寄存器地址 + 寄存器地址数量 + 校验码

    • 响应:从站地址 + 功能码 + 发送给主站的数据字节数 + 数据 + 校验码

我们的 easyeai-api 软件开源库对复杂的消息格式和收发操作进行了统一封装,使用户能够通过简单便捷的调用方式实现 Modbus 通信功能。

3.2. 快速开始

3.2.1 开发环境准备

在 PC 端 Ubuntu 系统中运行 run 脚本,进入 EASY-EAI 编译环境。具体步骤如下。

Terminal window
cd ~/develop_environment
./run.sh 2204

3.2.2 下载源码并编译示例程序

在 EASY-EAI 编译环境中,创建用于保存源码仓库的管理目录。

Terminal window
cd /opt
mkdir EASY-EAI-Toolkit
cd EASY-EAI-Toolkit

https://dl.dragonwake.com/download/rv1126b/embedded/EASY-EAI-Toolkit-1126B/Demos.zip

从上述链接下载 Demos.zip 压缩文件,上传到虚拟机的 /opt/EASY-EAI-Toolkit 目录并解压。

进入对应示例程序目录并执行编译操作。具体命令如下。

Terminal window
cd EASY-EAI-Toolkit-1126B/Demos/netProtocol-modbus/
./build.sh

💡 注意:由于依赖库放置在板端,交叉编译过程中必须保持 /mnt 挂载。

MODBUS 示例构建结果

MODBUS 示例构建结果

3.2.3 运行示例程序

通过串口调试或 SSH 调试进入板端后台,并切换到示例程序部署所在位置,如下所示。

Terminal window
cd /userdata/Demo/netProtocol-modbus

MODBUS 示例目录

MODBUS 示例目录

运行示例程序的命令如下。

Terminal window
./test-modbus_tcp_master & ./test-modbus_tcp_slave

3.2.4 実行結果

TCP 模式的运行结果如下。

MODBUS TCP 运行结果

MODBUS TCP 运行结果

如果需要改为 RTU 模式,可以自行修改代码。

  • 代码路径:EASY-EAI-Toolkit-1126B/Demos/netProtocol-modbus/test-modbus_tcp_slave.c

MODBUS RTU 代码修改位置

MODBUS RTU 代码修改位置

有关 API 的详细说明以及 API 调用(该示例程序的源代码),请参阅以下说明。

3.3. MODBUS 库函数说明

本章介绍 EASY EAI 的 MODBUS 库函数使用方法。

3.3.1 引用(包含)方法

EASY EAI api 库位于本仓库的 easyeai-api 目录中。为了便于用户在本地项目中直接调用我们的 EASY EAI api 库,下面列出了项目中需要链接的库和头文件等。

说明CMake 中的写法Makefile 中的写法
api.cmake${netProtocol_root}/modbus/api.cmake
头文件目录${MODBUS_INCLUDE_DIRS}-I ../../easyeai-api/netProtocol/modbus
源码目录${MODBUS_SOURCE_DIRS}../../easyeai-api/netProtocol/modbus
库目录
链接参数${MODBUS_LIBS}

API 源码路径为 EASY-EAI-Toolkit-1126B/easyeai-api/netProtocol/modbus/。可以通过源码查看接口实现,也可以修改源码。

3.3.2 创建实例

通过 TCP 方式创建并初始化 Modbus 实例。

Terminal window
modbus_t\* modbus_new_tcp(const char \*ip, int port);
函数名:modbus_new_tcp()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ip:IP 地址

port:端口号
返回值成功:Modbus 实例

失败:NULL
注意事项

3.3.3 设置从站 ID

设置从站 ID 的函数原型如下。

Terminal window
void modbus_set_slave(modbus_t \*ctx, int slave);
函数名:modbus_set_slave()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

slave:从站 ID
返回值成功:0

失败:-1
注意事项

3.4 与从站连接

与从站建立连接的函数原型如下。

Terminal window
void modbus_connect(modbus_t \*ctx);
函数名:modbus_connect()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例
返回值成功:0

失败:-1
注意事项

3.4.1 寄存器操作(功能码对应函数)

3.4.1.1 读取线圈状态(功能码:0x01)

可以读取连续多个线圈状态。

Terminal window
int modbus_read_bits(modbus_t \*ctx, int addr, int nb, uint8_t \*dest);
函数名:modbus_read_bits()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:寄存器起始地址

nb:寄存器数量

dest:获取到的状态值
返回值读取到的寄存器数量(失败时为 -1)
注意事项

3.4.1.2 读取输入状态(功能码:0x02)

可以读取连续多个输入状态。

Terminal window
int modbus_read_input_bits(modbus_t \*ctx, int addr, int nb, uint8_t \*dest);
函数名:modbus_read_input_bits()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:寄存器起始地址

nb:寄存器数量

dest:获取到的状态值
返回值成功:返回 nb 的值(失败时为 -1)
注意事项

3.4.1.3 读取保持寄存器(功能码:0x03)

可以读取连续多个保持寄存器的值。

Terminal window
int modbus_read_registers(modbus_t \*ctx, int addr, int nb, uint16_t \*dest);
函数名:modbus_read_registers()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:寄存器起始地址

nb:寄存器数量

dest:获取到的寄存器值
返回值成功:读取到的寄存器数量

失败:-1
注意事项

3.4.1.4 读取输入寄存器(功能码:0x04)

可以读取连续多个输入寄存器的值。

Terminal window
int modbus_read_input_registers(modbus_t \*ctx, int addr, int nb, uint16_t \*dest);
函数名:modbus_read_input_registers()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:寄存器起始地址

nb:寄存器数量

dest:获取到的寄存器值
返回值成功:读取到的寄存器数量

失败:-1
注意事项

3.4.1.5 写入单个线圈状态(功能码:0x05)

Terminal window
int modbus_write_bit(modbus_t \*ctx, int addr, int status);
函数名:modbus_write_bit()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:线圈地址

status:线圈状态
返回值成功:0

失败:-1
注意事项

3.4.1.6 写入多个连续线圈状态(功能码:15)

Terminal window
int modbus_write_bits(modbus_t \*ctx, int addr, int nb, const uint8_t \*src);
函数名:modbus_write_bits()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:线圈起始地址

nb:线圈数量

src:要写入的多个线圈状态
返回值成功:0

失败:-1
注意事项

3.4.1.7 写入单个寄存器(功能码:0x06)

Terminal window
int modbus_write_register(modbus_t \*ctx, int addr, int value);
函数名:modbus_write_register()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:寄存器地址

value:寄存器值
返回值成功:0

失败:-1
注意事项

3.4.1.8 写入多个连续寄存器(功能码:16)

Terminal window
int modbus_write_registers(modbus_t \*ctx, int addr, int nb, const uint16_t \*src);
函数名:modbus_write_registers()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例

addr:寄存器起始地址

nb:寄存器数量

src:要写入的多个寄存器值
返回值成功:0

失败:-1
注意事项

3.4.2 关闭套接字

关闭套接字的函数原型如下。

Terminal window
void modbus_close(modbus_t \*ctx);
函数名:modbus_close()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例
返回值
注意事项

3.4.3 释放实例

释放实例的函数原型如下。

Terminal window
void modbus_free(modbus_t \*ctx);
函数名:modbus_free()详细信息
头文件easyeai-api/netProtocol/modbus/modbus.h
输入参数ctx:Modbus 实例
返回值
注意事项