物联网
定义是什么
物联网,物的互联网
- 物,实体,设备,是主体
- 互联网,在线,有网
现代的物联网产品一定是”物“通过某种方式接入了互联网
物联网困境
- 多样性的设备和协议,统一这些设备和协议,使他们能够相互通信和协调工作是一个挑战
- 海量设备接入,设备管理对网络带宽、通信协议以及平台服务架构都带来了巨大的挑战
- 不可靠的网络环境,网络环境复杂且不可靠、内存和闪存容量小、处理器能力有限
- 安全和隐私保护,物联网中设备长手机和传输敏感数据,安全和因素保护是至关重要的
- 数据处理和管理,物联网系统生成大量数据,包括数据的传输、存储、实时性处理和分析,是一个调整
- 互操作性和标准化,知道和遵循同一个通信标志和协议,促进设备和系统直接的互联舞台,是一个重要的难题
常用协议
- MQTT,消息队列遥测传输协议
- 满足低电量消耗 和 网络带宽的需求
- 保证物联网通信可靠
- MQTT-SN,MQTT协议传感器版本
- 运行在UDP上
- CoAP指令,运行在资源比较紧张的设备上的协议
- 运行在UDP上
- 小巧,最小数据包只有四字节
- 采用C/S架构
- 请求-响应的交互模式
- 客户端发送请求
- 服务器处理
- 服务器生成响应
- 服务器发送响应
- 客户端接收响应
- LwM2M,适合物联网的轻量级协议
- 底层使用CoAP协议,运行在UDP或SMS之上
- SMS,用短信作为信息传输的载体
- HTTP,互联网广泛应用的协议
- 适合硬件资源很充沛的设备
- LoRaWAN协议,低功率广域网协议
- 运行在物理层/数据链路层
- 解决如何接入互联网的问题
- 距离远、低功耗
- 通过TCP或者UDP协议传输的数据协议包
- NB-Iot,接入互联网物理机/数据链路层
- 运行在蜂窝网络,消耗带宽低
- 可以直接部署在GSM和LTE网络
MQTT解决了那些物联网困境
- 低带宽和不稳定网络
- 大规模设备管理
- 节能和资源受限设备
- 异构设备和交互的操作型
- 可靠性和消息传递保证
JSON
什么是JSON
一种轻量级的数据交换格式,易于理解和使用的文本格式
本质:JSON本质就是一个字符串
字符集:必须是UTF-8,可以在字符串类型的值前加编码转义符
为什么要用JSON
为什么取代了XML,称为物联网场景数据传输的首选
JSON | XML | |
---|---|---|
数据体积 | 体积小,文本格式简介 网络传输和存储占用更少带宽 | 体积大,使用大量标签和属性 对存储和网络要求高 |
解析速度 | 解析速度快,结构简单语法清晰 | 解析速度慢,语法复杂 |
阅读和编写 | 易于阅读 | 冗长复杂,不方便阅读 缺少注释的支持和标签的歧义性 |
可移植性 | 可移植性好,独立于编程语言和平台的格式 | |
支持 | 很多平台原生支持JSON,无需额外库和插件 | 没有直接集成,没有内置的支持 |
可嵌套性 | 支持嵌套,可以包含对象和数字 | |
应用领域 | 适合数据交互,数据传输快速,轻量的场合 | 适合数据结构复杂的表示和扩展 |
总结 | 更适合物联网场景 |
JSON格式
格式:大括号里面是键和值
键与值之间用" : “隔开
键值之间用” , “隔开,最后一个键值后没有” , "
注意:
- 空格与换行不影响键值格式
- JSON中需要换行,需要在相应位置添加换行符(依照操作系统决定)
- 字符串中有引号,引号需要加转义
格式1:
{
"key":"value", //字符串类型
"key1":123 //数字数据类型(包括:整数、小数、负数),没有长度限制
"key2":{ //对象,JSON嵌套,作为key内容存在
"name":"迟仪鑫",
"qq":2488701239
}
"key3":[1,2,3,4], //数组,可以是字符串、数字,对象
"key4":null //空值
}
格式2:
{"key":"value","key1":"value1"}
//去掉换行符,传输时节省内存和网络带宽
什么是序列化
将数据对象转换为JSON字符串的过程
序列化过程中,数据对象中的属性和值被转换为JSON格式的键值,并按照JSON语法规则进行组织
什么是反序列化
将JSON字符串转换为数据对象的过程
在反序列化过程中,JSON字符串被解析,键值被还原为数据对象的属性和值
MQTT协议基础
术语
- 网络连接,基于TCP,提供有序、可靠、双向字节流传输
- 应用消息,应用消息通过MQTT传输,关联服务质量和主题
- 客户端,使用MQTT的程序或设备
- 发布应用消息给相关客户端
- 订阅以请求接受相关的应用消息、
- 取消订阅以移除接受应用消息的请求
- 从服务器断开连接
- 服务端,作为发送消息的客户端和请求订阅客户端之间的中介
- 接受来自客户端的网络连接
- 接受客户端发布的应用消息
- 处理客户端的订阅和取消订阅请求
- 转发应用消息给符合条件的客户端订阅
- 订阅,包含一个主题过滤器和一个最大的服务质量的风景
- 主题名,附加在消息生的一个标签
- 主题过滤器,订阅中包含一个表达式,用于标识一个或多个主题
- 会话,客户端和服务端之间的状态交互
- 控制报文,通过网络连接发送的信息数据包
什么是MQTT
一个客户端/服务端架构的**“发布/订阅"模式的"轻量级”**的消息传输协议,被设计为高效、简单和2易于实现,适用于各种网络环境和设备
MQTT协议是应用层协议
MQTT协议基于TCP/IP协议
MQTT传输是以数据报进行传输,传输是以二进制形式进行的
注意:
- MQTT是一种协议
- MQTT.fx是一种工具
消息队列遥测
- 最初是连接传参设备和传感器,实现物联网通信
- 传输时,使用队列进行存储和管理,确保消息可靠和异步处理
- 遥测,值MQTT协议传输和收集来自远程设备的遥测数据
与消息队列区别
消息队列 | MQTT | |
---|---|---|
创建 | 发送消息前要创建队列 | 可以直接订阅主题,发送消息 |
消息 | 读走后消息消失 | 没人读,消息丢弃 |
设备 | 一对一 | 一对一,一对多,多对一 |
数据特点
- 轻量级,协议头部信息小,有效减少了数据传输的开销,适合带宽有限的网络环境
- 保留消息,新的消息保留在代理服务器上,新的订阅者订阅使可以接收到最新的消息
- 心跳机制,保证客户端和代理服务器之间会定期发送心跳消息
- 安全性,MQTT提高了多种安全机制保护通信安全
- 加密传输数据
- 身份验证
- 访问控制列表
- 消息保留和持久性,设备在离线期间仍可以接收到最新的消息,确保重要消息可靠传递
- 可扩展性,从小型部署到到大型全球部署都有应用
- 易于集成和实现,MQTT协议是简单、清晰且易于实现的,机会可以在任何平台和编程语言上进行开发
传输特点
- 采用TCP协议的应用层
- 采用C/S架构,客户端©,代理服务器(S)
- 使用订阅/发布模式,将消息的发送方和接收方解耦
- Qos有三种类型
- 、收发异步,发送方不需要等待收发应答
订阅/发布
发布时,设备将信息发布给代理,代理接收到数据转发给订阅设备
- 一对一
- 一对多,类似于广播
- 多对一,物联网场景,多个传感器对应一个客户端
订阅发布机制
消息处理:代理接收到发布者的消息,将该消息转发给当前订阅者,如果没有订阅者则消息会被丢弃
会话存储:将消息存储在独立于代理的持久会话中,即使订阅者断开,会话不会消息,发布者发布消息会存储进持久会话中,这些消息等到客户端再次上线不需要重新订阅,就会拿到消息
优点:
- 安全,通信双方不需要直接相连,双方不知道对方的代理,不需要暴露给所有人
- 代理长期在线,持久性连接,实时消息传递,离线消息处理,复杂均衡和容错性、高可靠和持久性
- 一个主题可以有多个发布者或多个接收者
中网和特性:发布者不知道订阅者是否成功接收,需要添加请求和应答机制
特性
客户端订阅和发布消息时,相互独立,空间上可以分离,时间上可以异步
- 相互可独立,客户端独立,彼此不知道
- 空间可分离,客户端彼此可以不在一个地方
- 时间可异步,信息发送和接收无需同步
网络层
最底层是TCP/IP,利于保证简单和易于实现的特点,降低集成难度
对于消息有序、可靠的要求上,MQTT和TCP目标是一致的
注意:TCP仍有可能因为网络断开而丢失消息
消息可靠
-
MQTT通过消息服务和持有规划机制共同保证了消息的可靠到达,最大程度上避免了消息丢失
- 消息等级0,消息可能会丢失,完全依赖TCP
- 消息等级1,消息不会丢失,但可能重复
- 消息等级3,消息不会对手也不会重复
-
假死状态
客户端定期发送心跳包报文
-
遗嘱消息
客户端在意外断开连接时发送一条预定义的消息给代理服务器,这个消息叫做遗嘱消息
遗嘱消息是用于通知其他阅览相同主题的客户端,发布者已经离线或连接中断
-
保留消息
在代理外部添加消息存储或消息队列系统,代理并不会保留消息
代理会保留某一主题发布的最后一条消息,当订阅端上线并重新订阅这个主题是,代理会将保留的消息进行下发
MQTT通信
主题(topic)/通配符
-
编码,UTF-8
-
最大长度,65535
-
区分大小写
-
可以通过"/"划分主题层级
-
配合主题通配符,一次订阅多个主题
-
+:单层通配符
- 一个主题可以出现多个单层通配符
- 可以在任意位置
-
#:多层通配符,包括0个层级
-
home/# 可以匹配home
-
必须是主题最后一个字符
-
-
可以在主题中同时使用单层通配符和多次通配符
-
-
注意:
- 通配符必须独自占用一个层级
- 通配符只能在订阅和取消订阅是使用
- 系统消息,$开头的主题仅供服务器使用,客户端禁止使用,但客户端可以订阅该主题
- 通配符并不会匹配带$的主题,该主题需要进行单独订阅
- topic和topic类不同
- topic是消息传输的中介
- 同一产品下不同设备的Topic集合,用${deviceName}同配唯一的设备
主题规范
- 不建议以" / "开头或结尾
- 尽量使用ASCII字符
- 不建议在主题使用空格
- 不建议使用#订阅所有主题
- 尽量使用简洁的主题
- 在主题中包含标识信息
通信流程
- 发布方和订阅方都建立到了代理的TCP连接
- 订阅方告诉代理它要订阅的主题
- 发布方将消息发送到代理,指定消息的主题
- 代理接收到消息后,检查都有那些订阅方订阅了这个主题,将消息发送到这些订阅方
- 订阅方从代理获取该消息
- 如果某个订阅方离线,代理可以帮它保存消息,订阅方下次连接代理是,再将保存的消息发送给订阅方
代理功能
- 对客户端接入进行授权,对客户端进行权限控制
- 横向扩展,满足海量客户端的接入
- 较好的接入性,接入现有的业务系统
- 易于监控,满足高可用性
常用代理
Mosaquitto、EMQ X、HiveMQ、VerneMQ
报文格式
格式:二进制数据包
作用:MQTT通过交换预定义的MQTT控制报文来通信
组成:固定报头、可变报头、有限载荷
组成 | 含义 | 包含 |
---|---|---|
固定报头 | 必须存在,用于描述报文信息。 | 数据包类型、对应标识、数据包大小 |
可变报头 | 不一定存在。主要看什么样子类型的报文 | 由数据包决定 |
有效载荷部分 | 内容。也是通信信息存放的地方。知识有时候会存放一些额外的信息,如:客户ID | 具体数据 |
固定报头
大小:2byte
组成:
- MQTT报文类型,0.5byte(4~7)
- 指定控制报文类型的标志位,0.5byte(0~3)
- 剩余长度,1~4字节,表示当前报文剩余部分字节数
- 小于128的值,使用单字节编码
- 大于128的值,使用低7位标识有效位,最高位标识是否有更多字节(延续)
数据包类型
名称 | 值 | 方向 | 描述 |
---|---|---|---|
Reserved | 0 | 不可用 | 保留位 |
CONNECT | 1 | Client到Broker | client请求连接到Broker |
CONNACK | 2 | Broker到Client | 连接确认 |
PUBLISH | 3 | 双向 | 发布消息 |
PUBACK | 4 | 双向 | 发布确认 |
PUBREC | 5 | 双向 | 发布收到 |
PUBREL | 6 | 双向 | 发布释放 |
PUBCOMP | 7 | 双向 | 发布完成 |
SUBSCRIBE | 8 | Client到Broker | Client请求订阅 |
SUBACK | 9 | Broker到Client | 请阅确认 |
UNSUBSCRIBE | 10 | Client到Broker | client请求取消订阅 |
UNSUNACK | 11 | Broker到Client | 取消订阅确认 |
PINGREQ | 12 | Client到Broker | PING请求 |
PINGREQ | 13 | Broker到Client | PING应答 |
DISCONNECT | 14 | Client到Broker | Client主动中断连接 |
Reserved | 15 | 不可以 | 保留位 |
数据包标识位
数据包 | 标识位 | Bit3 | Bit2 | Bit1 | Bit0 |
---|---|---|---|---|---|
CONNECT | 保留位 | 0 | 0 | 0 | 0 |
CONNACK | 保留位 | 0 | 0 | 0 | 0 |
PUBLISH | MQTT 3.1.1使用 | DUP | QoS | QoS | RETAIN |
PUBACK | 保留位 | 0 | 0 | 0 | 0 |
PUBREC | 保留位 | 0 | 0 | 0 | 0 |
PUBREL | 保留位 | 0 | 0 | 0 | 0 |
PUBCOMP | 保留位 | 0 | 0 | 0 | 0 |
SUBSCRIBE | 保留位 | 0 | 0 | 0 | 0 |
SUBACK | 保留位 | 0 | 0 | 0 | 0 |
UNSUBSCRIBE | 保留位 | 0 | 0 | 0 | 0 |
UNSUBACK | 保留位 | 0 | 0 | 0 | 0 |
PINGREQ | 保留位 | 0 | 0 | 0 | 0 |
PINGRESP | 保留位 | 0 | 0 | 0 | 0 |
DISCONNECT | 保留位 | 0 | 0 | 0 | 0 |
可变报头
组成:协议名、协议级别、连接标志、保持连接
有效载荷
组成:客户端标识符、用户名、密码
连接与断联流程
建立连接
在进行订阅发布直接需要连接到代理
流程:
- Client向代理发送一个connect数据包
- 代理收到数据包后进行回复
- 成功,回复一个connect包,该包的返回码为0
- 失败,回复一个connect包,该包的返回码为非0,数值表示失败的原语
Connect包
-
固定头,数据包字段值为1,数据包标识位保留
-
可变头,协议名称、协议版本、连接表示、Keepale
- 协议名称,“04MQTT”,UTF-8字符集
- 协议版本为一个字节
- MQTT3.1,版本号为3
- MQTT3.1.1,版本号为4
- MQTT5,版本号为5
- 链接标识 ,1字节,如果两个客户端使用相同的标识连接,第二个连接成功后第一个将断开
值 7 6 5 4 3 2 1 0 用户名标识 密码标识 遗愿消息标识(Retain) 遗愿消息标识(Qos) 遗愿消息标识(Qos) 遗愿标识 会话清除标识(clean) 保留 是否有用户名字段 是否有密码字段 是否保留消息 遗愿消息等级高位 遗愿消息等级低位 是否使用遗愿消息 是否建立持久会话 -
消息体,客户端标识符、遗愿主题、遗愿QOS、遗愿消息、用户名和密码
- 客户端标识符,标识client的字段
- 用户名,存在,代理会对用户名和密码进行验证zz
- 密码,存在,代理会对用户名和密码进行验证
- 遗愿主题,client非正常断开连接时,代理向遗愿主题发布该字段指定的内容
- 遗愿消息,client非正常断开连接时,发布该字段指定的内容
Connect ACK包
-
固定报头,数据包字段值为2,标识位保留,剩余长度固定为2
-
可变报头,固定两字节
-
确认标识,1~7位固定为0,0位为0或1
-
返回码,表示是否连接成功
-
Return Code 连接状态 0 连接已建立 1 连接被拒绝,不允许的协议版本 2 连接被拒绝,Client Identifier(标识)被拒绝 3 连接被拒绝,服务器不可用 4 连接被拒绝,错误的用户名或密码 5 连接被拒绝,未授权
-
断开连接
Client主动断开连接
步骤:
- Client主动向Broket发送一个Dis Connect数据包
- 关闭底层TCP连接
为什么不直接断开TCP:
- 发送后断开,代理知道结束数据传输,不会发送遗嘱消息
- 直接断开TCP,代理会认为异常断开,发送遗嘱消息
DISCONNECT报文
- 只有固定报头
- 数据类型为14,DISCONNECT
- 标识位保留
- 剩余长度为0
Broket主动断开连接
broket主动断开,长时间没有收到Broekt数据包
方式:直接关闭底层TCP
注意:MQTT库实现的client被动断开后自动重连
订阅与发布的流程
发布消息
- 客户端A连接到代理
- 客户端B连接到代理,并订阅Topic1
- 客户端A给代理发送一个数据包,该包主题为Topic1
- 代理收到客户端1发送的消息,发现客户端B订阅了Topic1,通过发送PUBLISH数据包方式将消息转发到ClientB
- ClientB从代理接收到该消息
为什么先订阅后发布:如果先发布后订阅,则代理看见该消息没有订阅者,则该消息会被丢弃
publish数据包
作用:用于在Sender和Receiver之间传输消息
报文:
- 固定头
- 数据包类型,值为3
- 标志位
- 消息重复标识(DUP),1bit,为1时,该消息为重发消息
- Qos,2bit,代表服务质量等级
- retain标识,1bit,当为1时,代理保存该消息
- 数据包剩余长度
- 可变头
- 主题名,2字节(0~65535),UTF-8编码
- 包标识符(Packet Identifier),只会在Qos1或Qos2的情况下出现
- 消息体,该数据包要发送的数据,可以是二进制、文本或JSON
puback包
- 固定头,数据包类型,值为3,标志位保留,数据长度为2
- 可变头,2字节标识符
- 消息体,不存在
订阅消息
- 客户端向代理发送一个SUBSCRIBE数据包,该包包含了Client想要订阅的主题及其他参数
- 代理接收到SUBSCRIBE数据包后,向Client发送给SUBACK数据包作为应答
SUBSCRIBE数据包
- 固定报头
- 数据包类型,固定为8
- 数据包标志位,保留
- 数据包剩余长度
- 可变报头,1~2字节,唯一标识一个数据包
- 消息体,主要由主题列表构成,Client想要订阅的主题,可以通过通配符同时订阅多个主题,必须是一个UTF-8的编码
- SUBSCRIBE,该主题叫做主题过滤器
- Qos,消息等级
SUBACK数据包
- 固定报头,数据包类型为9,数据包标识位保留,数据包剩余长度
- 可变报头,2byte包标识符
- 消息体,返回码,与主题列表对应,每个返回码为1Byte
返回码 | 含义 |
---|---|
0 | 订阅成功,最大可以Qos为0 |
1 | 订阅成功,最大可以Qos为1 |
2 | 订阅成功,最大可以Qos为2 |
128 | 订阅失败 |
取消订阅
- client向Brokey发送一个UNSUBSCRIBE数据包,其中Client想要取消订阅的主题
- 代理收到UNSUNSCRIBE数据包后,Client发送一个UNSUBACK数据包作为应答
UNSUBSCRIBE数据包
- 固定头,数据包类型为10,数据包标识位为保留,数据包剩余长度
- 可变头,2字节标识符
- 消息体,包含要取消订阅的主题过滤器列表
- 注意:取消时通配符没有作用
UNSUBACK数据包
- 固定头,数据包类型为11,数据包标识位为保留,数据包剩余长度为2
- 可变头,2字节标识符
- 消息体,不存在
MQTT Qos
MQTT保证消息稳定传输的机制,包括消息应答、存储和重传
注意:这个保证是客户端和代理之间的
- Qos=0,至多一次,没有应答机制
- Qos=1,至少一次,有应答机制
- Qos=1,只有一次
Qos0
发送到向接收端发送一个包含数据的PUBLISH数据包,不会关注最终结果
优点:占用资源最少
缺点:信息是否可靠由网络状况决定
Qos1
在Qos0的基础上添加了应答机制
- 发送端发送PUBLISH数据包,并在本地保存
- 接收端接收到这个数据包后,向发送到发送确认包
- 发送端收到确认包后,找到本地保存的数据包并删除
- 若发送端在接收到确认包前会一直向发送端发送
Qos2
- 发送端发送消息,发布者将消息发送给接收端
- 接收端确认接收后,向发送者发送PUBREC消息,表示确认接收
- 发布者确认,接收到PUBREC消息后,向代理发送一个PUBREL消息表示接收确认的回应
- 消息代理确认完成,接收到PUBREL消息后,会向发布者发送一个PUBCOMP消息,表示消息发布的最终确认
服务降级
服务端会选项发布消息和订阅消息中较低的Qos来实现消息传输,这也被称作服务降级
保留消息
作用
- 客户端一但订阅主题,可以立即获得该主题的消息
注意
- 每一个主题只有一个保留消息
- 订阅一个主题后只能收到一个保留消息
- 保留消息为空时,表示保留消息被闪存
MQTT保活
仅仅是TCP层连接状态检测是不够的,MQTT有一套Keepalive机制
传递时MQTT从换地Keepalive参数,MQTT越低在1.5XKeepalive的时间间隔内,如果代理没有收到来自Client的任何数据包,则认为带了和Client之间的连接以及断开
通过PINGREQ/PINGRESP数据包满足Keepalive的约定和连接的侦测
PINGREQ数据包
- 固定头,数据包类型为12,数据包标识保留,剩余长度固定为0
- 可变报头没有
- 消息体没有
PINGRESP数据包
- 固定头,数据包类型为13,数据包标识保留,剩余长度固定为0
- 可变报头没有
- 消息体没有
注意
- 如果在间隔时间内有数据包传输,则client没有在使用PINGREQ的必要了
- Keepalive的值是由Client指定的,不同的Client可以指定不同的值
- Keepalive的最大值为18个小时12分15秒
- keepalive的值如果设为0,代表不使用Keepalive机制
UDP/TCP
区别是什么
特点 | UDP | TCP |
---|---|---|
是否由连接 | 无连接 | 有链接 |
传输基本单位 | 数据包 | 数据流 |
传输速度 | 传输速度快,且天生高并发 | 传输速度较慢 |
可靠性 | 不可靠 | 可靠 |
udp传输基本单位
基本单位:数据包
UDP数据包是一个独立的,完整的数据单元,它具有包含源和目的端口号的头部信息
每个数据包都是独立的,可以独立地接收和发送不会受到其他数据报的影响
TCP传输基本单位
基本单位:数据流
将应用城市数据视为一系列字节,没有固定的分隔单位。TCP协议在发送数据时,会将数据流切分成合适的大小,添加TCP头部信息,封装成TCP段进行传输
TCP会重新组装收到的TCP段,还原为原始的字节流
为什么UDP高并发
- 无连接性
- 简单的头部格式
- 较低的开销
- 实时性要求