写点什么

基于阿里云物联网平台设计的实时图传系统 _ 采用 MQTT 协议传输图像

作者:DS小龙哥
  • 2023-04-19
    重庆
  • 本文字数:6245 字

    阅读完需:约 20 分钟

一、项目功能介绍

当前基于 MQTT 协议设计了一个实时图传系统,通过这个项目来演示,两个 MQTT 设备如何互相订阅,进行消息流转。 在阿里云服务器上创建 2 个设备,分为为设备 A 和设备 B;设备 A 负责采集本地摄像头画面上传,设备 B 负责接收设备 A 上传的数据然后解析显示出来。在阿里云服务器上需要配置云产品流转,让设备 A 的数据上传后自动发送给设备 B。这样就完成了视频画面数据的流转。不过因为阿里云的最大数据限制,每次最大发送 10240 字节的数据。


当前的项目是采用 MQTT 协议实现,那么先来了解一下什么是 MQTT 协议。


软件采用 Qt 设计,QT 版本是 5.12.6


设备 A 的功能:获取摄像头的数据---》缩放成 240*320---》编码成 JPEG 格式---》转码成 base64---》组合成 MQTT 报文---》上传到服务器。


设备 B 的功能:订阅设备 A 上传的数据,得到数据后解析出源格式数据---》将图像画面渲染显示出来。


软件运行效果:



总结软件运行的体验效果:


(1) 非常流畅。两个窗口肉眼感觉不到延迟。


(2)服务器不要钱。


这个方案验证之后,可以衍生出很多实际的例子了:比如, 单片机+摄像头+MQTT 协议 也可以做为图传发送端。 联网可以使用:WIFI 或者 4G 模块、5G 模块。

1.1 MQTT 协议

MQTT (Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅的消息传输协议,它可以在客户端和服务器之间进行双向通信。MQTT 被设计为适用于低带宽、不稳定网络连接的物联网设备通信。


MQTT 具有以下主要特点:


(1)发布/订阅模型:客户端可以选择订阅一个或多个主题(topic),并接收与这些主题相关的消息;同时,客户端也可以发布消息到一个或多个主题上。


(2)轻量级:MQTT 的协议头非常小,最小只有 2 字节,这使得它非常适合于传输数据量较小的 IoT 设备。


(3)QoS(服务质量)支持:MQTT 支持三种不同的 QoS 级别,分别是“至多一次”、“至少一次”和“恰好一次”,可以根据应用场景的需要进行选择。


(4)保留消息:MQTT 服务器可以将最新的消息保留在主题中,并让新的订阅者能够读取先前发布的消息。


(5)遗嘱消息:当客户端与服务器连接异常断开时,服务器可以向其他订阅了该主题的客户端发送遗嘱消息,以实现更可靠的消息传输。


总之,MQTT 是一种非常适合物联网设备通信的协议,它具有轻量级、灵活性高、易于实现、可靠性强等优点,已经被广泛地应用于各种物联网场景中。

1.2 MQTT 协议载体

MQTT 协议是基于 TCP 协议传输报文的。MQTT 使用 TCP/IP 协议栈来实现通信,因此它具有 TCP 协议的一些特性,如可靠性、流控制和建立持久连接等特点。


在 MQTT 连接建立时,客户端需要通过 TCP 连接到 MQTT 服务器,并进行握手协商,包括协议版本、客户端标识符、遗嘱消息、QoS 级别等信息,以确保双方能够正确地交换数据。一旦握手成功,客户端和服务器之间就建立了一个持久化的 TCP 连接,可以随时进行消息传输。


由于 TCP 协议本身已经提供了一定程度的可靠性保证,因此 MQTT 协议只需要在 TCP 的基础上实现发布/订阅机制、QoS 级别控制、保留消息等特性即可,从而使得它成为一种轻量级且高效的物联网通信协议。

1.3 JSON 里如何保存图片数据?

在 JSON 中保存图片数据通常需要将图片转换为二进制数据,并将其编码成 Base64 字符串,然后将该字符串作为 JSON 对象的属性值进行传输。


Base64 编码是一种将二进制数据转换为 ASCII 字符的方法,它使用 64 个字符来表示任意序列的二进制数据。Base64 编码后的数据长度会比原始二进制数据略长,但可以方便地被转换为文本格式并在网络上进行传输。


以下是一个示例 JSON 对象,其中包含了一个 Base64 编码后的图片数据:


{  "imageData": "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBD...",  "imageName": "my_image.png"}
复制代码


在这个示例中,imageData属性表示图片数据的 Base64 编码字符串,imageName属性表示图片文件名。在接收到 JSON 对象后,可以通过解码 Base64 字符串并将其保存为二进制数据,再将其写入磁盘或者显示在应用程序中。


需要注意的是,由于 Base64 编码后的数据量相对较大,因此在实际应用中,如果需要传输大量的图片数据,建议使用其他更适合的数据传输方式,如 MQTT 协议、WebSocket 等。

1.4 MQTT 协议最大能传多少有效字节的数据?

MQTT 协议本身没有限制数据包的大小,但是它需要遵循底层传输协议(TCP/IP)的限制和约束。在实际应用中,MQTT 协议能够传输的有效数据量是受多种因素影响的,如网络带宽、QoS 级别、MQTT 消息头部信息等。


一般来说,在默认情况下,MQTT 协议对于单个消息的有效载荷有一个限制,即不超过 256MB。这个限制主要由 MQTT 协议的消息长度字段决定,该字段的最大值是 4 字节,因此最大能表示 2^32-1 个字节的消息长度,即约为 4GB。然而,在实际应用中,由于网络带宽和设备性能等方面的限制,很难实现传输如此巨大的消息。


另外,需要注意的是,如果使用较高级别的 QoS,如“至少一次”或“恰好一次”,则 MQTT 协议会对每条消息进行确认和重传,这可能会导致更多的网络流量和延迟。因此,在选择 QoS 级别时,需要根据应用场景和网络环境的实际情况进行优化和调整,以充分利用 MQTT 协议的特点和优势。

三、阿里云服务器创建

官网地址: https://iot.console.aliyun.com/lk/summary/new

3.1 创建产品


3.2 添加设备





{  "ProductKey": "a12qAqNZg3i",  "DeviceName": "video_de1",  "DeviceSecret": "206a4bc03642930542a9bcb8925b9a0f"}
复制代码


创建完成。


3.3 创建自定义属性

在产品页面的,找到功能定义。




最大一次只能传递 10KB。





3.4 MQTT 服务器地址和端口

关于 MQTT 协议登录所需要的参数官方说明文档: https://help.aliyun.com/document_detail/140507.html?spm=a2c4g.11186623.6.571.1e417544OGPj2y


阿里云物联网服务器的域名规则如下:


物联网平台的域名格式为:productKey.iot-as-mqtt.cn-shanghai.aliyuncs.com,其中productKey是您在物联网平台上创建的产品的标识符,cn-shanghai表示物联网服务器所在的地区。
MQTT协议的域名格式为:productKey.iot-as-mqtt.cn-shanghai.aliyuncs.com,其中productKey是您在物联网平台上创建的产品的标识符,cn-shanghai表示物联网服务器所在的地区。
HTTPS协议的域名格式为:productKey.iot-as-http.cn-shanghai.aliyuncs.com,其中productKey是您在物联网平台上创建的产品的标识符,cn-shanghai表示物联网服务器所在的地区。
需要注意的是,以上的域名规则中,productKey需要替换成你在物联网平台上创建产品时生成的实际productKey。
复制代码


下面是阿里云国内的服务器地域和可用区详情: 地域名称  所在城市  Region ID  可用区数量华北 1  青岛  cn-qingdao      2华北 2  北京  cn-beijing      10华北 3  张家口  cn-zhangjiakou  3华北 5  呼和浩特  cn-huhehaote  2华北 6  乌兰察布  cn-wulanchabu  3华东 1  杭州  cn-hangzhou      8华东 2  上海  cn-shanghai    8华南 1  深圳  cn-shenzhen     6华南 2  河源  cn-heyuan      2华南 3  广州  cn-guangzhou  2西南 1  成都  cn-chengdu      2
端口号是:1883
我的设备参数:{ "ProductKey": "a12qAqNZg3i", "DeviceName": "video_de1", "DeviceSecret": "206a4bc03642930542a9bcb8925b9a0f"}
经过上面的格式解释,我的阿里云服务器登录的域名就是(选择的是上海服务器):a12qAqNZg3i.iot-as-mqtt.cn-shanghai.aliyuncs.com
复制代码



解析域名对应的 IP 地址:



Microsoft Windows [版本 10.0.19044.2604](c) Microsoft Corporation。保留所有权利。
C:\Users\11266>ping a12qAqNZg3i.iot-as-mqtt.cn-shanghai.aliyuncs.com
正在 Ping vpc-sh-prod.mqtt.iotgds.aliyuncs.com.gds.alibabadns.com [47.103.191.238] 具有 32 字节的数据:来自 47.103.191.238 的回复: 字节=32 时间=40ms TTL=88来自 47.103.191.238 的回复: 字节=32 时间=40ms TTL=88来自 47.103.191.238 的回复: 字节=32 时间=40ms TTL=88来自 47.103.191.238 的回复: 字节=32 时间=40ms TTL=88
47.103.191.238 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),往返行程的估计时间(以毫秒为单位): 最短 = 40ms,最长 = 40ms,平均 = 40ms
C:\Users\11266>
复制代码

3.5 MQTT 三元组格式

下载密码生成小工具:https://help.aliyun.com/document_detail/292635.htm?spm=a2c4g.11186623.0.0.5aaf635b3zgveM#section-jx3-u57-pmm



打开密码生成工具:



生成 MQTT 登录的密匙: 填入的参数就是前面创建设备得到信息。



mqttClientId: video_de1|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_de1&a12qAqNZg3i
password: 02F7190BE8C33C1A8009EDBAF824BFDC6784FC67
复制代码

3.6 主题发布与订阅的格式

在产品页面可以看到主题格式: https://iot.console.aliyun.com/product/productDetail/a1cMlEwEwjg/func?current=2



总结:


发布主题:/sys/a12qAqNZg3i/video_de1/thing/event/property/post上报属性消息的格式:  {"method":"thing.event.property.post","params":{"image":"1234567890"}}
订阅主题:/sys/a12qAqNZg3i/video_de1/thing/service/property/set
复制代码

3.7 MQTT 设备登录

利用 MQTT 客户端完成设备登录测试。


IP地址:47.103.191.238
端口号:1883
mqttClientId: video_de1|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_de1&a12qAqNZg3i
password: 02F7190BE8C33C1A8009EDBAF824BFDC6784FC67

发布主题:/sys/a12qAqNZg3i/video_de1/thing/event/property/post上报属性消息的格式: {"method":"thing.event.property.post","params":{"image":"1234567890"}}
订阅主题:/sys/a12qAqNZg3i/video_de1/thing/service/property/set
复制代码


对号入座填入参数,测试主题订阅,主题发布:



数据接收成功:



到此服务器创建成功。

3.8 继续创建设备 2

监控设备有两个,1 个设备为摄像头图片发送端,一个设备是图片接收显示端。





{  "ProductKey": "a12qAqNZg3i",  "DeviceName": "video_dev2",  "DeviceSecret": "30ebb8ffc4316fbe957fcfb13bdaec01"}
复制代码


创建成功。



接下来生成设备 2 的 MQTT 三元组密匙,和前面一样的方法。



mqttClientId: video_dev2|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_dev2&a12qAqNZg3i
password: 15D2C020586E165E6A35BB2FA4DEB9DD59F3E73E
复制代码


参数总结:


IP地址:47.103.191.238
端口号:1883
mqttClientId: video_dev2|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_dev2&a12qAqNZg3i
password: 15D2C020586E165E6A35BB2FA4DEB9DD59F3E73E

发布主题:/sys/a12qAqNZg3i/video_dev2/thing/event/property/post
上报属性消息的格式: {"method":"thing.event.property.post","params":{"image":"abcdefg"}}
订阅主题:/sys/a12qAqNZg3i/video_dev2/thing/service/property/set
复制代码

四、云产品流转

4.1 创建解析器





创建完成。


4.2 创建规则




添加主题:



设置数据目的:






编写解析器脚本:



帮助文档地址:https://help.aliyun.com/document_detail/270937.html




下面编写代码,获取设备 1 上传的数据,转发给设备 2。


//通过payload函数,获取设备上报的消息内容,并按照JSON格式转换。var data = payload("json");//直接流转物模型上报数据。writeIotTopic(1000, "/a12qAqNZg3i/video_dev2/user/get", data)
复制代码



写好解析器就发布。


在云产品流转的首页启动解析器。



4.3 测试两个设备的订阅

设备 1 的参数:


IP地址:47.103.191.238端口号:1883mqttClientId:  video_de1|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|username: video_de1&a12qAqNZg3ipassword: 02F7190BE8C33C1A8009EDBAF824BFDC6784FC67
设备1发布主题:主题格式:/a12qAqNZg3i/video_de1/user/update数据内容:{"method":"thing.event.property.post","params":{"image":"1234567890"}}
复制代码


设备 2 的参数:


IP地址:47.103.191.238端口号:1883mqttClientId: video_dev2|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|username:  video_dev2&a12qAqNZg3ipassword:  15D2C020586E165E6A35BB2FA4DEB9DD59F3E73E
设备2订阅主题:主题格式:/a12qAqNZg3i/video_dev2/user/get
复制代码


五、项目开发

5.1 base64 编码和解码实现

摄像头采集图像数据之后会编码 成 base64 格式的字符串,再通过 MQTT 协议上传到物联网服务器。 下面就是 base64 编码和解码的实现代码。


const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//进行base64编码//bindata:进行编码的图片数据//base64:转换后的base64编码//binlength:图片大小char * base64_encode( u8 * bindata, char * base64, u32 binlength ){ u32 i, j; u8 current;
for ( i = 0, j = 0 ; i < binlength ; i += 3 ) { current = (bindata[i] >> 2) ; current &= (u8)0x3F; base64[j++] = base64char[(int)current];
current = ( (u8)(bindata[i] << 4 ) ) & ( (u8)0x30 ) ; if ( i + 1 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; base64[j++] = '='; break; } current |= ( (u8)(bindata[i+1] >> 4) ) & ( (u8) 0x0F ); base64[j++] = base64char[(int)current];
current = ( (u8)(bindata[i+1] << 2) ) & ( (u8)0x3C ) ; if ( i + 2 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; break; } current |= ( (u8)(bindata[i+2] >> 6) ) & ( (u8) 0x03 ); base64[j++] = base64char[(int)current];
current = ( (u8)bindata[i+2] ) & ( (u8)0x3F ) ; base64[j++] = base64char[(int)current]; } base64[j] = '\0'; return base64;}
//解码base64//base64:base64编码//bindata:图片数据int base64_decode( const char * base64, u8 * bindata ){ u32 i, j; u8 k; u8 temp[4]; for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 ) { memset( temp, 0xFF, sizeof(temp) ); for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i] ) temp[0]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+1] ) temp[1]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+2] ) temp[2]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+3] ) temp[3]= k; }
bindata[j++] = ((u8)(((u8)(temp[0] << 2))&0xFC)) | ((u8)((u8)(temp[1]>>4)&0x03)); if ( base64[i+2] == '=' ) break;
bindata[j++] = ((u8)(((u8)(temp[1] << 4))&0xF0)) | ((u8)((u8)(temp[2]>>2)&0x0F)); if ( base64[i+3] == '=' ) break;
bindata[j++] = ((u8)(((u8)(temp[2] << 6))&0xF0)) | ((u8)(temp[3]&0x3F)); } return j;}
复制代码

5.3 软件设计

5.4 运行效果



发布于: 2023-04-19阅读数: 58
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022-01-06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
基于阿里云物联网平台设计的实时图传系统_采用MQTT协议传输图像_三周年连更_DS小龙哥_InfoQ写作社区