写点什么

IoT 设备发送 MQTT 请求上云协议讲解——基础知识

作者:阿里云AIoT
  • 2023-01-12
    浙江
  • 本文字数:7298 字

    阅读完需:约 24 分钟

IoT 设备发送 MQTT 请求上云的曲折经历

为了搞清楚 IoT 设备从传感器获取到数据,通过网络发送到云端的整个网络过程,我们先来看一下网络分层模型:

上图中例举了网络分层中最常见的协议:

  • 应用层:应用程序负责将数据以相应规则(协议)进行包装,发给传输层

MQTT:消息队列遥测传输

CoAP:受限应用协议

HTTP:超文本传输协议

FTP:文件传输协议

SMTP:简单邮件传送协议

  • 传输层:负责将应用层传过来的数据进行分组,为确保终端接收数据的顺序和完整性,会对每个分组进行标记,交给网络层

TCP:传输控制协议

UDP:用户数据协议

  • 网络层:负责将传输层发来的数据分组发送到目标终端

IP:网际协议

ICMP:互联网控制报文协议

IGMP:互联网组管理协议

  • 链路层:为网络层发送和接收数据单元

ARP:地址解析协议

RARP:逆地址解析协议


  封装 和 分用  


数据在经过每一层的时候都要被对应的协议包装,即封装 (Encapsulation),到达终端的时候,要一层一层的解包,即分用(Demultiplexing)。


发送时,设备采集的业务数据被应用程序封装为 MQTT 报文,每一层会将上层传过来的报文作为本层的数据块,并添加自己的首部,其中包含了协议标识,这一整体作为本层报文向下传递。


接收时,数据自下而上流动,经过每一层时被去掉报文首部,根据报文标识确定正确的上层协议,最终到应用层被应用程序处理。


IoT 设备采集的业务数据被设备端上的应用程序封装为 MQTT 报文,MQTT 报文会以数据流的形式通过一条已经建立的 TCP 长连接按序传输,TCP 收到数据流后会将其分割成小的数据块,每个小块被添加的 TCP 首部与数据块共同组成了 TCP 分组,分组经由网络层发送,网络层遵循 IP 协议,当收到分组发送请求后,会将分组其放入 IP 数据报,填充报头,将数据报发经由链路层发送出去。


云端系统从链路层接收到数据请求后,进入网络层对数据进行解析,交给给传输层,校验分组顺序和完整性,从数据块中取出数据,得到 MQTT 报文,交给应用层进行处理。这个过程会逐层剥离报头还原出 IoT 设备采集的业务数据。


  应用层 -MQTT 协议 


MQTT 是一个客户端服务端架构的发布/订阅模式的消息传输协议。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT)。


MQTT 协议的数据包格式非常简单,由固定报头(Fixed header)、可变报头(Variable header)、有效载荷(Payload)三个部分组成。

固定报头:包含控制报文类型,标志位和剩余长度。

MQTT 报文的首字节高 4 位(bit7~bit4)表示控制报文类型,总共可以表示 16 种协议类型:

MQTT 报文的首字节低 4 位(bit4~bit0)用于指定数据包的标志位,仅 PUBLISH 控制报文有使用。

剩余长度: MQTT 报文的第 2 字节开始是用于标识 MQTT 数据包长度的字段,最少一个字节,最大四个字节,每一个字节的低 7 位用于标识值,范围为 0~127。


可变报头:存在于部分类型的 MQTT 数据包中,具体内容由相应类型的数据包决定。


有效载荷:存在于部分 MQTT 数据包中,存储消息的具体业务数据。  


传输层-TCP 协议  **


MQTT 连接是建立在 TCP 连接的基础之上的,TCP 提供可靠的数据连接。当要传输一个 MQTT 报文时,报文数据会以流的形式通过一条已经打开的 TCP 连接按顺序传输,TCP 会将收到的数据分成小块,每块是一个 TCP 分组。


由于数据是分成小块发送的,所以完整可靠的数据传输主要体现在:分组是否完整、分组顺序是否正常、分组是否损坏、分组数据是否重复。这些可以通过 TCP 的检验和、序列号、确认应答、重发控制、连接管理和窗口机制来控制。


TCP 是传输控制协议,传输控制主要依赖首部包含的 6 个标志,它们控制报文的传输状态,以及发送端和接收端应对数据采取的动作。当它们的值为 1 时,标志对应的各自功能才允许被执行,比如当 URG 为 1 时,报文首部的紧急指针部分才有效。


  • URG 紧急指针

  • ACK 确认序号有效

  • PSH 接收方应该尽快将这个报文段交给应用层。

  • RST 重建连接

  • SYN 同步序号用来发起一个连接

  • FIN 发端完成发送任务

image.png

源端口和目的端口:标识发送方和接收方的端口号,一个 TCP 连接通过 4 个值确认:源 IP、源端口、目的 IP、目的端口,其中源 IP 和目的 IP 包含在 IP 分组内。


首部长度:表示 TCP 首部的字节长度,也能标记出从多少个字节开始,才是需要传输的数据。


TCP 段序号:本段报文发送的数据第一个字节的序号,每段报文中的数据的每个字节都有序号,第一个字节的序号从 0 开始,依次加 1,加到 2 的 32 次方减 1 后再次从 0 开始。


TCP 段确认序号 :当首部标志 ACK 为 1 时,确认序号有效。TCP 段被接收端接收后,会回送给发送端一个确认号,为上次接受的最后一个字节序号加 1。检验和:由发送端计算,接收端验证,如果接收方检测到检验和不正确,表明该 TCP 段可能有损坏,会被丢弃,同时接收端向回送一个重复的确认号(与最近的一次正确的报文传输的确认号重复),表明接收到的 TCP 段是错误的,并告知自己希望收到的序号。这时发送端需要立即重传出错的 TCP 段。


紧急指针:当首部标志 URG 为 1 时,紧急指针有效,表示发送端向接收端要发送紧急数据。紧急指针是一个正偏移量,它和 TCP 段序号相加,计算出紧急数据的最后一个字节的序号。比如接收方接收到数据,从序号为 1000 的字节开始读取,紧急指针为 1000,那么紧急数据就是序号从 1000 到 2000 之间的字节。这些数据由接收方决定如何处理。


窗口尺寸:决定了 TCP 一次成块数据流的吞吐量。需要注意的是,它表示的是发送一方的允许对方发送的数据量,比如发送方首部中的窗口大小为 1000,就表示发送方最多可以接受对方发来的 1000 个字节的数据量。这与发送方的数据缓存空间有关,会影响 TCP 的性能。


首部标志 PSH:如果需要告诉接收方将数据立即全部提交给接收进程,发送方需要将 PSH 置为 1,这里的数据是和 PSH 一起传送的数据以及之前接收到的全部数据。如果接收方收到了 PSH 为 1 的标志,需要立即将数据提交给接收进程,不用再等待有没有其他数据进来。


复位标志 RST:当 RST 为 1 时,表示连接出现了异常情况,接收方将终止连接,通知应用层重新建立连接。


同步序号 SYN:用来建立连接,涉及到 TCP 的三次握手。

  1. 开始建立连接时,客户端向服务器发送一个 TCP 分组,分组首部的 SYN 为 1,并携带一个初始序号,表明这是一个连接请求。

  2. 如果服务器接受了连接,会向客户端发送一个 TCP 分组,分组中会包含 SYN 和 ACK,都为 1,同时包含一个确认序号,值为来自客户端的初始序号 + 1,表示连接已经被接受。

  3. 客户端收到上一步发来的分组后,会再向服务器发送一段确认报文分组,ACK 为 1,会再次携带确认序号,值是第二步来自客户端的确认序号 + 1。服务端收到确认信息后,进入已经连接的状态。


在第三步的确认分组中,是可以携带要发送的数据的。


连接终止标志 FIN:用来关闭连接,当一端完成数据发送任务后会发送一个 FIN 标志来终止连接,但因为 TCP 在两个方向(C-S,S-C)上会有数据传递,每个方向有各自的发送 FIN & 确认关闭流程,所以会有四次交互,也称为四次挥手。

  1. 如果客户端应用层的数据发送完毕,会导致客户端的 TCP 报文发送一个 FIN,告知服务器准备关闭数据传送。

  2. 服务器接收到这个标志后,它发回一个 ACK,确认序号为收到的序号加 1,同时 TCP 还要向应用程序发一个文件结束符。

  3. 此时服务器关闭这个方向的连接,导致它的 TCP 也会发送一个 FIN。

  4. 客户端接收到之后发回一个确认 ACK,序号为收到的序号 + 1,连接完全关闭。


TCP 段序号与确认序号保证了数据的顺序,检验和确保数据的完整性,紧急指针保证紧急数据可被及时处理。另外,TCP 还有一些超时重传、 拥塞避免、慢启动的机制,都可以保证分组数据按照顺序完整的传到目标端。


  网络层- IP 协议  


如果说 TCP 分组是包装货物的集装箱,那么 IP 就是运送集装箱的卡车。IP 协议提供了两个节点之间的连接,保证将 TCP 数据尽可能快地从源端送到终端,但却不能保证传输的可靠性。


IP 层会将上层传过来的 TCP 分组封装,带上自己的首部,再进行选路、是否分片以及重组的工作,最终到达目的地,这个过程中,IP 首部起了重要的作用,下面让我们看一下首部的结构。

版本:表示当前 IP 协议的版本,目前版本号是 4,还有一种是 6,也就是 IPV4 和 IPV6,如果发送和接收这两端的版本不一致,那么当前 IP 数据报会被丢弃。


首部长度:整个首部的长度,最长为 60 字节。


服务类型(TOS):用来区分服务的类型,但其实 IP 层在工作的时候一直没有实际使用过,现有的 TOS 只有 4bit 的子字段,和 1bit 的未用位。未用位必须置为 0。TOS 的 4 个 bit 中只能将一个置成 1,用来表示当前服务类型。4bit 对应的 4 个服务类型分别为:最小时延、最大吞吐量、最高可靠性和最小费用。


总长度:表示当前的数据报报文的总长度,单位为字节,可以结合首部长度计算出报文内数据的大小以及起始位置。


下面这三个首部字段涉及到 IP 数据报的分片与重组过程,由于网络层一般会限制每个数据帧的最大长度,IP 层发送数据报会在选路的同时查询当前设备网络层的每个数据帧的最大传输长度,一旦超出,数据报就会被进行分片,到达目的地之后再进行重组,此时就会用以下三个字段作为重组依据。需要注意的是:因为存在选路的过程,数据报经过的每层路由设备对于数据帧的最大传输长度都不同,所以分片可能发生在任意一次选路的过程中。


分组标识:这个标识相当于 ID,每成功发送一个分片,IP 层就会把这个分组 ID 加 1。


标志:共占用三位,分别是 R、D、M,R 目前还没有被使用,有用的是 D、和 M。这个字段表示了数据报的分片行为。D 如果为 1 的话,表示数据无需分片,一次传输完;M 如果为 1,表示数据是分片的,后边还有数据,当它为 0 时,就表示当前数据报是最后一个分片,或者只有这一个分片。


片偏移:标识了当前分片距离原始数据报开始处的位置,分片之后,每一片的总长度会改成这一片的长度值,而不是整个数据报的长度。


生存时间:(TTL) 可以决定数据报是否被丢弃。因为 IP 发送数据是逐跳的,数据有可能在被设置了路由功能的不同的 IP 层之间转发,所以生存时间表示了数据报最多个可以经过多少个处理过它的路由,每经过一层路由,值减去 1,当值为 0 时数据报就被丢弃,并且发送一个带有错误消息的报文(ICMP,IP 层的组成部分,被用来传递一些错误信息)给源端。生存时间可以有效解决数据报在一个路由环路中一直转发的问题。


首部检验和:校验数据报的完整性,发送端对首部进行求和,将结果存在检验和中,接收端再计算一遍,如果计算结果与存在检验和中的结果一致,则说明传输过程是 OK 的,否则这个数据报就会被丢弃。


上层协议:决定了接收端在分用的时候将数据交给哪个上层协议去处理,例如 TCP 或者 UDP。


源 IP:记录了发送端的 IP,在回送错误消息时用到。


目的 IP:表示目的 IP,每一次选路都要以它来做决策。


路由选择

因为 IP 首部只包含了目的 IP 地址,并不体现完整的路径,当向外发送数据时,IP 层会根据目的 IP 在本机路由表中的查询结果来做出选路决策,数据报会逐跳地被运送到目的地,这里的每一跳,就是一次路由选择。


IP 层既可配置成路由器,也可以配置成主机。当配置成路由功能时,可以对数据报进行转发,配置成主机时,如果目的 IP 不是本机 IP,数据报会被丢弃。


具有路由功能的 IP 层在当目标 IP 不是本机地址的时候是根据什么判断转发到哪一站呢?要理解这个问题,需要先明白路由表的结构,以下是 IP 层维护的路由表:


  • Destination(目的 IP):表示 IP 数据报最终要到达或者经过的网络地址或者主机地址。

  • Gateway(下一跳地址):当前维护路由表设备的相邻路由器的地址

  • Flags(标志):表示当前这一条路由记录的属性,具体用五个不同的标志来表示:

U:该路由可以使用

G:如果有这个标志,表示是下一跳是一个网关,如果没有,表示下一跳是和当前设备在一个网段,也就是可以直接把数据报发过去

H: 下一跳是一个主机还是一个网络,有这个标志,表示主机,没有,则表示下一跳的路由是一个网络

D:该路由是由重定向报文创建的

M:该路由已被重定向报文修改

  • Interface:当前路由项的物理端口


每收到一个数据报时候,IP 层就会根据目的 IP 在路由表里查询,根据查询状态会导向三种结果:

  • 找到了与目的 IP 完全匹配的路由项,将报文发给该路由项的下一站路由(Gateway)或者网络接口(Interface)

  • 找到了与目的 IP 的网络号匹配的路由项,将报文发给该路由项的下一站路由(Gateway)或者网络接口(Interface)

  • 前两者都没有找到,就看路由表里有没有默认路由项(default),有的话发给它指定的下一站路由(Gateway)


要是上边三个都没有结果,那么数据报就不能被发送。IP 数据报就是这样一跳一跳地被送往目的主机的,但数据报有固有的长度,一旦超出了目的主机的 MTU,就会被分片。


数据报分片的概念

TCP 在进行握手的时候,会根据目的端 IP 层的最大传输单元(MTU)来决定 TCP 数据每次能传输的最大数据量(MSS),之后 TCP 会对数据依照 MSS 来进行分组,每个分组会被包装进一个 IP 数据报内。当 IP 数据报经过选路过程中的任意一层路由时,有可能被 MTU 限制住从而被分片,这时 IP 首部的 3bit 标志中的 M 标志被置为 1,表示需要分片。每个分片的首部基本一样,只是片偏移有所不同。依据片偏移,这些分片在目的端被重组成一个完整的 IP 数据报(一个 TCP 分组)。IP 传输是无序的,所以得到的数据报也是无序的,但如果数据完整,TCP 会根据首部中的字段对其进行排序。一旦 IP 分片丢失,IP 层无法组成完整的数据报,就会告诉 TCP 层,TCP 进行重传。  


链路层-ARP 协议  **


当 IP 层将数据封装好之后,只有目标主机的 IP 地址。光有 IP 地址并不能直接把数据报发送过去,因为每一台硬件设备都有自己的 MAC 地址,是一个 48bit 的值。现在知道目标 IP 的地址,需要找到这个 IP 对应的 MAC 地址。这个过程要通过查询路由表,再结合链路层的 ARP 协议,最终获得目标 IP 对应的 MAC 地址。ARP 协议实现了从 IP 地址到 MAC 地址的映射。一开始,起点并不知道目标的 MAC 地址,只有目标 IP,要获取这个地址就涉及到了 ARP 的请求和应答。同样,ARP 也有自己的分组,先看一下分组格式。

以太网目的地址: 目的端的 MAC 地址,当 ARP 缓存表中没有的时候,这里为广播地址。


以太网源地址: 发送端的 MAC 地址。


帧类型: 不同的帧类型有不同的格式和 MTU 值,不同的类型有不同的编号,这里 ARP 对应的编号是 0x0806。


硬件类型: 指链路层网络类型,1 为以太网。


协议类型: 指的是要转换的地址类型,0x0800 为 IP 地址。比如将以太网地址转换为 IP 地址。


操作类型: 有四种,分别是 ARP 请求(1),ARP 应答(2),RARP 请求(3),RARP 应答(4)。


源 MAC 地址: 表示发送端 MAC 地址。


源 IP 地址: 表示发送端 IP 地址。


目的以太网地址: 表示目标设备的 MAC 物理地址。


目的 IP 地址: 表示目标设备的 IP 地址。


当两台设备发送报文之前,源端的链路层会用 ARP 协议去询问目的端的 MAC 地址,ARP 会将一个请求广播出去,以太网上的每一个主机都会收到这份广播,广播的目的是询问目标 IP 的 MAC 地址,内容主要是先介绍自己的 IP 和 MAC 地址,再询问如果你有目标 IP,请回复你的硬件地址。如果一个主机收到广播后看到自己有这个 IP,并且请求内有源 IP 和 MAC 地址,那么就会向源主机回应一个 ARP 应答。如果没有目标 IP,就会丢弃这个请求。可以看出请求是向外广播的,而应答是单独回应的。


但不能每次通信之前都去经历一次请求-应答过程,在成功地接收到应答之后,IP 和 MAC 地址的映射关系就会缓存在 ARP 缓存表中,有效期一般为 20 分钟,便于网络层下次直接进行封装,所以,完整的过程应该是:


IP 层接收到 TCP 分组后,发送或者封装之前,通过查询路由表:

  • 当目标 IP 和自己在同一个网段时,先去 ARP 缓存表里找有没有目标 IP 对应的 MAC 地址,有的话交给链路层进行封装发送出去。如果缓存表内没有,进行广播,获得 MAC 地址后缓存起来,IP 层再对 TCP 进行封装,然后交给链路层再封装发送出去。

  • 当目标 IP 和自己不在同一个网段,需要将报文发给默认的网关。如果 ARP 缓存表中有网关 IP 对应的 MAC 地址,那么交给链路层进行封装发送出去。如果没有,进行广播,获得地址后缓存起来,IP 层再对 TCP 进行封装,然后交给链路层再封装发送出去。


以太网数据帧

上面所有东西都准备好了,封装发送的其实是以太网数据帧。以太网目的地址、以太网源地址、帧类型这三者组成了帧首部。在首部之前还会插入前同步码和帧开始定界符,告知接收端做一些准备工作。帧检验序列 FCS 被添加进尾部,用来检测帧是否出错。

前同步码: 协调终端接收适配器的时钟频率,让它与发送端频率相同。


帧开始定界符: 帧开始的标志,表示帧信息要来了,准备接收。


目的地址: 接收帧的网络适配器的 MAC 地址,接收端收到帧时,会首先检查目的地址与本机地址是否相符,不是的话就会丢弃。


源地址: 发送端设备的 MAC 地址。


类型: 决定接收到帧之后将数据交由那种协议处理。


数据: 交给上层的数据。在本文的场景中指 IP 数据报。


帧检验序列: 检测这一帧是否出错,发送方计算帧的循环冗余码校验(CRC)值,把这个值写到帧里。接收方计算机重新计算 CRC,与 FCS 字段的值进行比较。如果两个值不相同,则表示传输过程中发生了数据丢失或改变。这时,就需要重新传输这一帧。


传输和接收

**

  • 接收到上层传过来的数据报之后,根据 MTU 以及数据报大小来决定是否分割成小块,也就是 IP 数据报被分片的过程。

  • 把数据报(块)封装成一帧,传给底层组件,底层组件将帧转换为比特流,并发送出去。

  • 以太网上的设备接收到帧,检查帧里边的目标地址,如果与本机地址匹配,帧就会被处理,一层一层向上传递(分用过程)。


结语

以上,我们梳理了 IoT 设备将传感器采集数据,被端上应用程序封装成 MQTT 报文,通过网络协议一层层封装,再到云端接收系统一层层拆分的完整网络过程,希望对大家认识物联网相关 MQTT,TCP,IP,ARP 网络协议有所帮助。


【往期回顾】

1、39张IoT传感器工作原理GIF图汇总

2、自建 MQTT 集群 迁移 阿里云IoT实践

3、智能手持测温枪开发实践

4、JMeter 压测 MQTT 服务性能实战

5、IoT物联网平台日志服务详解

6、工业 Modbus,电力104规约, 车联网JT808

7、网关与子设备上云开发实战

8、IoT中实现 M2M 设备之间联动


物联网平台产品介绍详情:https://www.aliyun.com/product/iot/iot_instc_public_cn


阿里云物联网平台客户交流群

用户头像

阿里云AIoT

关注

物联网内容搬运者 2022-04-22 加入

还未添加个人简介

评论

发布
暂无评论
IoT 设备发送 MQTT 请求上云协议讲解——基础知识_缓存_阿里云AIoT_InfoQ写作社区