精华内容
下载资源
问答
  • 网络协议

    千次阅读 2017-09-30 18:06:35
    网络协议:网络为进行数据交换而建立的规则局域网常用的协议: TCP/IP 协议 (目前最流行的协议,没有根本上不了网) NetBEUI IPX/SPX协议 (用来连接玩游戏的) 其中TCP/IP协议包括了上百个互为关联的协议(位于...

    网络协议:网络为进行数据交换而建立的规则

    局域网常用的协议:

    • TCP/IP 协议 (目前最流行的协议,没有根本上不了网)
    • NetBEUI
    • IPX/SPX协议 (用来连接玩游戏的)

    其中TCP/IP协议包括了上百个互为关联的协议(位于传输层)

    • Telnet 提供 远程登录功能
    • FTP 远程文件传输协议
    • SMTP 简单邮政传输协议
    • NFS 网络文件服务器
    • UDP 用户数据包协议,(位于传输层,和IP协议配合使用,在传输数据省去包头,不能提供数据包重传,所以适合传输较短的文件)

    TCP/IP 协议详解

    TCP/IP协议是基本的协议 由网络层的IP协议和传输层的TCP协议组成;该协议采用4层结构

    1. TCP (传输控制协议)
      TCP是面向连接的、可靠的、基于字节流的传输成通信协议

    TCP 头部

    英文版的

    中文版的

    一般情况下 TPC header 的长度是20个字节
    上述两图中需要注意的地方 :

    1. TCP layer 没有IP地址的概念,所以4个字节 是源端口和目的端口
    2. Sequence Number(序号):传输过程中,为每一个封包分配了一个序号保证网路传输数据的顺序性;
    3. Acknowledgment Number(确认号):用来确认收到相关封包,内容表示期望收到下一个报文的序列号,用来解决丢包问题
    4. TCP Flags: 标志数据包的属性,比如SYN,RST,FIN,PSH, URG, ACK,操控TCP的状态机
    5. Windows:滑动窗口,主要用于解决流控拥塞问题
    6. Checksum : 校验值
    7. Urgent Pointer : 紧急指针,可告知紧急的数据位置,需要Flag和U flag 配合使用
    8. TCP options :一般包含三次握手中,有option 选项!

      TCP Flags 解释 :

    9. URG 用来 督促中间层设备要要尽快处理这些数据;

    10. ACK : 表示应答域有效
    11. PSH : 数据包到达接收端以后,立即传送给应用程序,而不是排队等候;
    12. RST : 表示连接复位请求,用来复位那些产生错误的连接;
    13. SYN :用来建立连接
    14. FIN:表示发送端已经达到数据末尾,双方数据传输完成。

    TCP三次握手

    1、第一次握手:建立连接,客户端发送连接请求报文,将 SYN 位置为1,Seq为X,然后客户端等待状态,等待服务器确认;
    2、第二次握手; 服务器收到SYN报文段,对SYN进行确认。设置Acknowledgment Number(确认号)为X+1(seq+1);同时发送自己的SYN信息,将SYN位置为1,seq为y,服务器将信息放在报文段中,发送给客户端,服务器进行进行SYN_RECV状态
    3、第三次握手, 客户端接受到 SYN+ACK 报文段,将Acknowledgment Number确认号设置为y+1 向服务器发送ACK报文段,发送完毕,连接成功

    展开全文
  • TCP/IP协议简述

    千次阅读 多人点赞 2019-03-26 19:49:14
    TCP/IP协议是一个协议集合。TCP/IP协议族中有一个重要的概念是分层,TCP/IP协议按照层次分为以下四层。应用层、传输层、网络互连层、网络接口层。 互联网中信息以数据包的单位传输,不同的协议层对数据包有不同的...

    TCP/IP协议是一个协议集合。TCP/IP协议族中有一个重要的概念是分层,TCP/IP协议按照层次分为以下四层。应用层、传输层、网络互连层、网络接口层。
    在这里插入图片描述

    互联网中信息以数据包的单位传输,不同的协议层对数据包有不同的称谓,在传输层叫做段 (segment),在网络层叫做数据报 (datagram),在链路层叫做帧 (frame)

    发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息,这种把数据信息包装起来的做法称为封装(encapsulate)。数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理

    在这里插入图片描述

    • 应用层(负责包装数据)
      HTPP协议,生成针对目标服务器的请求报文。那报文包含啥呀,比如我web端或客户端要将一个“name”字段传到服务器,那么报文就是对name的包装,比如我是用get还是post请求方法,请求的URL是啥,内容实体"name",content-type等,虽然有些是你在代码里设置的,但是需要将你设置的内容按照http协议里要求的格式进行封装,然后服务器也会按照这个协议定义的格式进行解析,拿到"name"这个字段。所以可以简单的理解为对数据按一定格式包装,当然FTP协议也属于这一层,区别可自行搜索。在这一层的还有DNS(域名解析)服务,将URL解析成对应的IP地址,比如www.baidu.com会解析成192.166.xx.xx,用户通常使用域名来访问服务器,而不是IP地址,因为与一串数字的IP地址相比,用字母配合数字的表现形式来制定计算机名更符合人类的记忆习惯,查找过程如图:
      在这里插入图片描述
      HTTP是不保存状态的协议:HTTP协议自身不对请求和响应之间的通信状态进行保存、这是为了更快的处理大量事务,确保协议的可伸缩性。应用中为了实现保持登录状态功能引入了Cookie技术。
      TCP持久连接:
      在这里插入图片描述
      管线化:持久化接使得多数请求以管线化(pipelining)方式发送成为可能。 从前发送请求后需等待并收到响应,才能发送下一个请求。管线化化技术 出现后,不用等待响应亦可直接发送下一个请求。
      在这里插入图片描述
      Cookie交互场景
      在这里插入图片描述
    • 传输层(负责运输数据)
      应用层把要传输的数据包装好了以后,就会给到下一层,也就是传输层,传输层负责两台设备之间的数据运输,TCP和UDP都属于这层,TCP就是提供可靠的字节流服务。字节流服务,就是可以将大的数据分割成小的数据进行管理传输,可靠是指可以把数据准确可靠的传给对方。

    所谓的字节流服务(Byte Stream Service)是指,为了方便传输,将大块数据分割成以报文段(segment)为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。一言以蔽之,TCP 协议为了更容易传送大数据才把数据分割,而且 TCP 协议能够确认数据最终是否送达到对方。

    为了提供可靠的传输,TCP在正式传输数据前采用了三次握手的策略,一保证传输的可靠性,如图所示:
    在这里插入图片描述

    • 网络层(负责导航规划路线)
      传输层进行握手和传输数据的时候,如何找到对方的就得靠网络层了, IP协议就属于该层,IP协议的作用就是规划数据可以走哪条路到达服务器,并把数据给服务器,规划的前提是知道服务器的IP地址和服务器的MAC地址,IP地址是指上网设备在网络世界中被分配到的地址,MAC地址是指上网设备(手机、电脑)中网卡的编号。

    使用 ARP 协议凭借 MAC 地址进行通信
    IP 间的通信依赖 MAC 地址。在网络上,通信的双方在同一局域网(LAN)内的情况是很少的,通常是经过多台计算机和网络设备中转才能连接到对方。而在进行中转时,会利用下一站中转设备的 MAC 地址来搜索下一个中转目标。这时,会采用 ARP 协议(Address Resolution Protocol)。ARP 是一种用以解析地址的协议,根据通信方的 IP 地址就可以反查出对应的 MAC 地址。——《图解HTTP》

    IP地址已经在应用层通过DNS服务解析出来了,现在就差服务器的MAC地址,有了服务器的IP地址和MAC地址以后,就可以查找到服务器了。采用APR(Address Resolution Protocol)地址解析协议,就可以根据IP地址反查出电脑的MAC地址(服务器网卡的地址) 。但是互联网世界这么大,网线中间经过了无数个路由器进行连接中转(并不是咱们家里自己用的WIFI发射信号的路由器),所以每个路由器都只知道一部分电脑IP地址对应的MAC地址,所以根据APR协议查找MAC地址时可能需要中转好几次,如图:
    在这里插入图片描述

    • 链路层(中介)
      这一层就是硬件层面的东西了,说白了就是让计算机这块塑料金属组装的玩意和网络世界连接起来的硬件部分,比如网卡等。可以将网线传输过来的电信号,转成010101的数字信号,然后就可以变成我们想要的数据。

    用一张图总结一下:
    在这里插入图片描述
    参考资料来源:黑色蚂蚁_MGLMHSLZ1devmao

    展开全文
  • MQTT协议

    千次阅读 2016-04-26 21:48:31
    MQTT协议摘要MQ遥测传输(MQ Telemetry Transport,MQTT)是一个轻...在嵌入设备中运行,处理器和内存资源有限。 该协议的特性包括: 使用发布/订阅消息模式,提供一对多的消息分发,解除应用程序耦合。 消息传输对有

    MQTT协议


    摘要

    MQ遥测传输(MQ Telemetry Transport,MQTT)是一个轻量级的基于代理的发布/订阅式消息传输协议,它的设计目标是开放、简单、轻量和易于实现。这些特征使它适用于各种受限环境,比如,但不限于:

    • 网络代价昂贵,低带宽或不可靠。
    • 在嵌入设备中运行,处理器和内存资源有限。
      该协议的特性包括:
    • 使用发布/订阅消息模式,提供一对多的消息分发,解除应用程序耦合。
    • 消息传输对有效载荷内容不可知。
    • 使用TCP/IP提供基础网络连接。
    • 有3个消息发布服务质量级别:
      • “至多一次”,消息发布完全依赖于底层TCP/IP网络。消息有可能丢失或重复。这一级别可应用于如下情景,如环境传感器数据,丢失一次读记录无所谓,因为很快下一次读记录就会产生。
      • “至少一次”,确保消息到达,但消息重复有可能发生。
      • “只有一次”,确保消息到达且只到达一次。这一级别可用于如计费系统等场景,在计费系统中,消息丢失或重复可能会导致生成错误的费用。
    • 轻量传输,开销很小(固定头部的长度只有2字节),协议交换最小化,以降低网络流量。
    • 提供一种机制,当客户端异常中断时,利用 Last Will 和 Testament 特性来通知有关各方。

    1. 简介

    该协议规范主要分为3个主要部分:

    • 对所有类型的数据包都通用的消息格式
    • 每种特定数据包的具体细节
    • 数据包如何在服务器和客户端之间传输

    在附录中将介绍如何主题通配符(topic wildcards)的使用方法。

    1.1 V3.1与V3之间的变化

    MQTT V3.1中与MQTT V3之间的不同点如下所示:

    • 添加用户验证,用户名和密码现在可以在 CONNECT 数据包中一并发送。
    • 为解决一些安全问题,在 CONNACK 数据包中添加了新的返回码。
    • 当客户端发送未授权的 PUBLISH 或 SUBSCRIBE 命令时,客户端不会收到相应的通知,即客户端不知道命令不会被执行。而且即使命令未被执行,该MQTT流也应该正常完成。
    • MQTT中的字符串现在支持完整的UTF-8字符集,而不仅仅是US-ASCII子集。

    V3.1中,通过 CONNECT 包传送的协议版本号仍然是“3”,与V3相比没有变化。现存的基于MQTT V3的服务器实现须通过正确考虑“剩余长度(Remaining Length)字段”,以及相应地忽略多余的安全信息来接受来自V3.1协议的客户端的连接。

    2. 消息格式

    每个MQTT命令消息的消息头部都包含了一个固定头部。其中一些类型的消息可能还需要一个可变头部和一个有效载荷(可理解为消息体)。

    2.1 固定头部

    每个MQTT命令消息的消息头部都包含一个固定头部。固定头部的格式如下表如示。

    Byte 1
    包含消息类型和标志(包括DUP,QoS level和RETAIN)字段。

    Byte 2
    包含剩余长度字段(至少1个字节,最多4个字节)。

    byte 1:

    • DUP:重复交付

      当客户端或服务器试图重发 PUBLISH、PUBREL、SUBSRIBE、UNSUBSCRIBE 消息时,该标志位要被置位(即设为1)。这适用于消息的QoS标志值大于0的情况,此时消息确认是必需的。当DUP位被置位时,可变头部将包含一个消息ID。

      消息的接收者应当将该标志视为该消息之前可能已收到的提示消息,而不该依赖于它进行消息重复检测。

      目的:
      提示消息接收者该消息为重复消息(被置位,值为1时),可能已被收到

    • QoS:消息的交付质量级别

      该标志位标明 PUBLISH 消息的交付质量级别。

      QoS=0:至多交付一次(不需要确认回复)
      QoS=1:至少交付一次(需要确认回复)
      QoS=2:只交付一次(需要确认回复)
      QoS=3:保留的
      

    • RETAIN:保持

      该标志位只用于 PUBLISH 消息。当一个客户端发送一条 PUBLISH 消息给服务器,假设该消息所属的主题(topic)为topicA,如果该标志位被置位(1),服务器在将该条消息发布给当前的所有topicA的订阅者之后,还应当保持这条消息。

      当topicA出现了一个新的订阅者,则topicA的最后一条保持消息应当立即发给该订阅者。当然,如果不存在保持消息,则什么也不用发。
      当消息发布者以基于 “report by exception” 的方式发送消息时,这个功能就特别有用,因为这种情况下,消息发送间隔往往较长。这个功能使得新的订阅者可以立刻收到之前保持的或上一个确定有效的消息。

      当服务器收到某个主题的 PUBLISH 消息时,对于之前已经订阅该主题的客户端,服务器将给这些客户端发送这一 PUBLISH 消息,发送前,服务器会将该消息的 RETAIN 标志置为0(即不置位),不管服务器之前收到该 PUBLISH 消息时其 RETAIN 标志是否被置位。这样做可以使得区分它接收到的 PUBLISH 消息是服务器之前保持的(RETAIN标志置位)还是即时收到的(RETAIN标志不置位)。

      保持消息应当在重启服务器后仍能保留。

      如果服务器收到有效载荷长度为0或重复主题的保持消息,服务器可以删除该保持消息。

      总结:

      RETAIN标志位只用于 PUBLISH 消息,当服务器收到某个主题的 PUBLISH 消息时,如果RETAIN标志位为1,则表示服务在将该消息发送给所有的已订阅该主题的订阅者后(发送前服务器将RETAIN标志置为0),还需保持这条消息,当有新增的订阅者时,再将这条消息发给新增的订阅者;如果RETAIN标志位为0,则不保持消息,也不用发给新增的订阅者。
      

      目的:

      1.将RETAIN标志位置为1,可使新的订阅者收到之前保持的或上一个确定有效的消息。
      2.区分新订阅者(RETAIN标志为1)和老订阅者(RETAIN标志为0)
      
    • Message Type:消息类型

      Reserved        0       保留
      CONNECT         1       客户端请求连接服务器
      CONNACK         2       连接确认
      PUBLISH         3       发布消息
      PUBACK          4       发布确认
      PUBREC          5       发布接收(有保证的交付第1部分)
      PUBREL          6       发布释放(有保证的交付第2部分)
      PUBCOMP         7       发布完成(有保证的交付第3部分)
      SUBSCRIBE       8       客户端订阅请求
      SUBACK          9       订阅确认
      UNSUBSCRIBE     10      客户端取消订阅请求
      UNSUBACK        11      取消订阅确认
      PINGREQ         12      PING请求
      PINGRESP        13      PING响应
      DISCONNECT      14      客户端断开连接
      Reserved        15      保留
      

    byte 2:

    剩余长度(Remaining Length)

    位置:byte 2(从byte 2,最大可至byte 5)

    该字段表示当前消息的剩余内容的字节数,包括可变头部和有效载荷的数据。

    该字段本身的字节数是根据可变头部和有效载荷的长度不同而变化的。该可变长度编码方案如下:每个字节的低7位(7-0位)编码剩余长度的数据,第8位表示后面是否还有编码剩余长度的字节。即每个字节编码128个值和一个“延续位”。所以只用一个字节时,最大只可表示127字节的长度。

    举例如下,十进制数字64只需用1个字节来编码,即0x40。 十进制数字321(=65 + 2x128)则需要用2个字节来编码,其中第1个字节为1100 0001,该字节的低7位表示65,第8位表示后面还有字节;第2个字节为0000 0010,表示2x128。

    协议限制该字段最大为4个字节,这允许应用程序发送的最大消息长度为268435455(256MB),即0xFF,0xFF,0xFF,0x7F。

    下表给出了增加该字段的字节数时相应可表示的剩余长度值。

    该编码方案的算法如下所示,输入为一个十进制数(X),输出为编码后的结果。

    do
      digit = X MOD 128
      X = X DIV 128
      // if there are more digits to encode, set the top bit of this digit
      if ( X > 0 )
        digit = digit OR 0x80
      endif
      'output' digit
    while ( X> 0 )
    

    其中,MOD是模运算符(在C语言中相当于%),DIV表示整数除法(在C语言中相当于/),OR是位或运算符(在C语言中相当于|)。

    相应地,剩余长度字段的解码算法如下所示:

    multiplier = 1
    value = 0
    do
      digit = 'next digit from stream'
      value += (digit AND 127) * multiplier
      multiplier *= 128
    while ((digit AND 128) != 0)
    

    其中,AND是位与运算符(在C语言中相当于&)。

    当该解码算法终止,value等于剩余长度的字节数。

    值得注意的是,剩余长度编码不是可变头部的一部分。剩余长度的值不包括用于编码剩余长度的字节数。这部分“增加的长度”(1-3字节)是固定头部的一部分,而不属于可变头部。

    译者注:可认为剩余长度字段虽然是固定的,但该字段的长度却是变化的(1-4字节)。

    2.2 可变头部(Variable header)

    某些类型的MQTT命令消息还包含了一个可变头部,它位于固定头部和有效载荷之间。

    可变的剩余长度字段(1-4字节)不是可变头部的一部分。剩余长度字段的值不包括该字段本身的长度。该值只包括可变头部和有效载荷。

    可变头部中各个字段的格式将在后续章节中进行详细介绍,介绍顺序与该字段在可变头部中的顺序一致。

    • 协议名称(Protocol name)

      协议名称字段只用于 MQTT CONNECT 消息的可变头部中。该字段以UTF编码方式显示

      协议名称:MQIsdp,大小写如上所示。

    • 协议版本(Protocol version)

      协议版本字段只用于 MQTT CONNECT 消息的可变头部中。

      该字段用8位无符号值来表示客户端所使用的协议修订级别。当前版本协议中该字段的值为3(0x03),如下表所示。

    • 连接标志(Connect flags)

      该字段用于 CONNECT 消息的可变头部中,占1字节,包括Clean session、Will、Will QoS和Retain标志。

      • Clean session 标志(位置:bit 1)

        如果没有被置位(即值为0),则当客户端断线时,服务器必须保存该客户端的订阅信息,包括断线期间发布的该客户端订阅的主题中交付质量级别为QoS 1和QoS2的消息,这样当客户端重连时,这部分消息能确保被送达到客户端。同时,服务器还必须保持客户端在断线的那个时刻正在传输中的消息的状态,直到客户端重新连接。
        
        如果被置位(即值为1),则服务器必须丢弃任何之前保持的该客户端的信息,将该连接视为“不存在(Clean)”。同时,当客户端断线时,服务器必须丢弃其所有状态。
        
        通常情况下,客户端会一直在其中一种模式下操作,不会进行切换。该选择取决于具体应用的需求。一个 Clean session 客户端将不会收到过时的信息,且它每次重连时都需要重新订阅主题。而一个 non-clean session客户端则不会漏接任何它在断线时服务器发布的交付质量级别为QoS 1和QoS 2的消息。QoS 0级别的消息由于只是尽可能的交付,所以它永远不会被存储保持。
        
        这个标志以前被称为“Clean start”。因为这个标志其实是作用于整个会话期间的,而不只是在连接的开始阶段,为了明确这个事实,所以将它重命名为“Clean session”。
        
        服务器可以提供一种管理机制,当确定一个客户端将永远不会重新连接时,可以清除该客户端的存储信息
        
        目的:通过设置Clean session标志(0/1)可以控制客户端不错过任何QoS>0的订阅信息(值为0时)或只接收在线时发布的订阅信息(值为1时)
        
      • Will 标志(位置:bit 2)

        Will消息是指当服务器与客户端通信过程中出现故障或客户端在保活时间内没有与服务器保持正常交流时,服务器特意发给客户端的消息。当客户端通过发送 DISCONNECT 消息正常断开时,Will消息不会发送。
        
        如果Will标志被置位,则Will QoS标志和Will Retain标志的设置将会发生作用,同时,在有效载荷里必须填写Will主题和Will消息内容字段。
        
      • Will QoS(位置:bit 4-3)

        Will QoS标志用来设置当客户端异常离线时,服务器发送的Will消息的交付质量级别。Will消息的内容在客户端发送的 CONNECT 消息里的有效载荷里填写。
        
        如果Will标志被置位,则Will QoS字段必须填写,否则该字段的值将被忽略。
        
        Will QoS字段的可选值有0(0x00),1(0x01)和2(0x02),格式如下表所示。
        
      • Will Retain 标志(位置:bit 5)

        Will Retain标志指明服务器是否需要保持客户端异常离线时发送给客户端的Will消息。
        
        如果Will标志被置位,则Will Retain标志必须填写,否则其将被忽略。
        
      • User name and password 标志(位置:bit 6-7)

        客户端在连接服务器时可以指定用户名和密码,通过将用户名标志和密码标志(可选)置位表明在 CONNECT 消息的有效载荷里包含有用户名和密码。
        
        如果将用户名标志置位,则必须在有效载荷里填写用户名字段,否则用户名字段将被忽略。同样地,如果密码标志被置位,则必须在有效载荷里填写密码字段,否则密码字段将被忽略。只提供密码而不提供用户名是不合法的。
        
        目的:置位后表明在 CONNECT 消息的有效载荷里包含有用户名和密码
        
      • 保活计时器(Keep Alive timer)

        保活计时器用于MQTT CONNECT 消息的可变头部中。
        
        保活计时器定义了服务器收到客户端消息的最大时间间隔,它以秒为单位。它使得服务器不需要等待漫长的TCP/IP超时就可以检测与客户端的网络连接是否断开。客户端有义务在每个保活时间间隔内至少发送一条消息给服务器。如果这期间没有业务相关的消息要发送,客户端则发送一个 PINGREQ 消息给服务器,相应地服务器返回一个 PINGRESQ 消息给客户端。
        
        如果服务器在1.5个保活时间(可宽容0.5个保活时间)内都没有收到客户端的消息,则服务器将其视为客户端发送了一个 DISCONNECT 消息,并断开与客户端的连接。这个动作不影响客户端的订阅。具体细节参见 DISCONNECT。
        
        如果客户端在发送 PINGQ 后的一个保活时间内没有收到服务器发来的 PINGRESP 消息,则客户端可以关闭TCP/IP套接字连接。
        
        保活计时器用2个字节来表示,时间单位为秒。实际设定的值由特定应用决定,不过通常它的值都设为数分钟,最大值接近18个小时。如果设为0,则表示客户端不断线。
        
        保活计时器的格式如下表所示。2个字节的顺序为先 MSB,再 LSB(大端模式)。
        
        目的:规定保活时间,在保活时间内客户端发送一个PINGREQ(期间内没有业务相关的消息发送),服务器端返回一个PINGRESQ,以此来表明服务器与客户端的网络是连接的;若规定时间内客户端没有发送或服务器没有返回,则服务器断开与客户端的连接
        

    • 连接返回码(Connect return code)

      连接返回码用于 CONNACK 消息的可变头部中。

      这个字段用一个无符号字节来表示返回码。这些值的含义如下表所示。值为0的返回码通常表示连接成功。

    • 主题名(Topic name)

      主题名用于 PUBLISH 消息的可变头部中。

      主题名决定消息要发送到哪个信息通道。订阅者使用主题名来决定他们要从哪些信息通道接收消息。

      主题名是一个UTF编码字符串。更多信息参见MQTT和UTF-8。主题名支持的最大字符度为32767。

    2.3 有效载荷

    以下类型的MQTT命令消息拥有一个有效载荷:

    • CONNECT

      该有效载荷包含了一个或多个UTF-8编码字符串。它们包括标识客户端的唯一标识符、Will主题和消息、要使用的用户名和密码。其中只有第一项是必选的,其余的取决于可变消息头部中的标志置位情况。

    • SUBSCRIBE

      该有效载荷包含一系列要订阅的主题名,以及每个主题的QoS级别。这些字符串都是UTF编码的。

    • SUBACK

      该有效载荷包含一系列授权过的QoS级别。它们是服务器管理员允许授权给客户端订阅的各个主题的QoS级别。授权的QoS级别顺序与相应订阅的主题的顺序保持一致。

    • PUBLISH

      该有效载荷只包含应用特定的数据。协议不对数据的属性和内容作任何假设,协议把消息的这部分内容视为一个BLOB。

      如果你想要对有效载荷数据进行压缩,你必须自己在有效载荷里定义合适的标志来处理压缩事宜。你不能在固定状况或可变头部里定义与特定应用相关的标志。

    2.4 消息标识符(Message Identifiers)

    消息标识符用于以下MQTT消息的可变头部中:PUBLISH,PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK。

    消息标识符(消息ID)字段只存在于固定头部中QoS标志值为1或2的消息中。更多信息可参见交付质量级别和消息流。

    消息ID用16位无符号整数来表示,在同一个方向上的在传消息ID必须是唯一的。它通常是逐个消息递增的,但不强制如此。

    客户端与它所连接的服务器一样,都需要维护自己的消息ID列表,二者的消息ID列表互不影响。客户端在发送一个消息ID为1的 PUBLISH 消息的同时也有可能收到来自服务器的消息ID为1的 PUBLISH 消息。

    表示消息ID的2个字节的顺序为先 MSB,再 LSB(大端模式)。

    不要使用值为0的消息ID。它是作为无效消息ID保留的。

    2.5 MQTT和UTF-8(MQTT and UTF-8)

    UTF-8是一种针对Unicode的可变长度字符编码,它优化了ASCII字符集的编码,以支持基于文本的通信。

    在MQTT中,字符串编码的头2个字节用来记录字符串的长度,如下表所示。

    字符串长度表示所有字符经过UTF-8编码后的字节数,而不是字符串中字符的个数。例如,经过UTF-8编码后的字符串 OTWP 如下表所示。

    Java中的 writeUTF() 和 readUTF() 数据流方法也使用这种格式。

    2.6 未使用的位(Unused bits)

    任何标明为未使用的位都应当置为0。

    3. 命令消息

    3.1 CONNECT - 客户端请求连接服务器

    当客户端与服务器的TCP/IP套接字连接建立起来之后,必须发送一个 CONNECT 消息流来建立一个协议级别的会话。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      DUP、QoS以及RETAIN标志在 CONNECT 消息中没有被使用到。

      剩余长度字段的值为可变头部(12字节)和有效载荷的字节数总和。剩余长度字段自身的长度可能大于1个字节。

    • 可变头部(Variable header)

      一个可变头部例子的格式如下表所示。

      其中,

      用户名标志置位(1)。

      密码标志置位(1)。

      Clean session标志置位(1)。

      保活计时器设置为10秒(0x000A)。

      Will 消息

      • Will标志置位(1)
      • Will QoS字段值为1
      • Will RETAIN标志不置位(0)
    • 有效载荷(Payload)

      CONNECT 消息的有效载荷根据可变头部中各标志位的置位情况,包含一个或多个UTF-8编码字符串。这些字符串如果出现的话,必须符合以下顺序:

      • 客户端ID

        这是第1个UTF编码字符串。客户端ID(Client ID)的长度为1至23个字符,服务器根据客户端ID可以指定到唯一的客户端。对于连接到某个服务器的所有客户端,它们的客户端ID必须都是唯一的,客户端ID还是处理QoS级别1和2消息的关键。如果发送的CONNECT 消息中客户端ID的长度大于23个字符,则服务器会回复一个返回码值为2(标识符被拒绝)的 CONNACK 消息。

      • Will主题

        如果Will标志被置位,则Will主题将是有效载荷中的下一个字符串。Will消息将会发送给Will主题。消息的QoS级别和RETAIN状态在可变头部的Will QoS和Will RETAIN标志中设置。

        尽管Will消息内容在 CONNECT 消息中是以UTF-8编码的,但当它最后被发送到Will主题时,只有消息的实际内容被发送,而不包括开头记录长度的2个字节。因而,消息必须只包含7-bits ASCII字符。

      • 用户名

        如果用户名标志被置位,则用户名将是有效载荷中的下一个字符串。用户名字段用于认证,标明了连接的用户的名字。建议用户名不超过12个字符,但不强制如此。

        值得注意的是,为了与MQTT V3版本协议兼容(V3中不支持用户名密码), 固定头部中的剩余长度字段的优先级应该高于用户名标志。服务器的实现必须允许用户名标志被置位,但不存在用户名字符串的情况。这是合法的,连接应该继续进行。

      • 密码

        如果密码标志被置位,则密码将是有效载荷中的下一个字符串。密码字段用于认证,对应于连接的用户名。建议密码不超过12个字符,但不强制如此。

        值得注意的是,为了与MQTT V3版本协议兼容(V3中不支持用户名密码), 固定头部中的剩余长度字段的优先级应该高于密码标志。服务器的实现必须允许密码标志被置位,但不存在密码字符串的情况。这是合法的,连接应该继续进行。

      • 回复(Response)

        服务器收到客户端发送的 CONNECT 消息后会回复一个 CONNACK 消息。

        如果在TCP/IP连接建立后的一段合理时间内服务器没有收到客户端发送的 CONNECT 消息,则服务器应该关闭这个连接。

        如果客户端在发送 CONNECT 消息后的一段合理时间内客户端没有收到服务器回复的 CONNACK 消息,则客户端应该关闭原先的TCP/IP连接。然后建立新的TCP/IP连接,并发送 CONNECT 消息以重起会话。

        以上两种场景中,一段合理时间的设置依赖于特定应用的需求和通信架构。

        如果尝试连接的客户端ID在服务器中已经存在,则服务器会断开“旧”的客户端并与新的客户端完成连接操作。

        如果客户端发送了一个不合法的 CONNECT 消息,包括提供了不合法的协议名和协议版本号,服务器应该断开连接。如果服务器可以从 CONNECT 消息中识别并且明确客户端使用了一个不合法的协议,服务器可以尝试在断开连接前回复一个 CONNACK 消息,告知客户端“Connection Refused: unacceptable protocol version”。

    3.2 CONNACK - 连接确认

    当客户端向服务器发起 CONNECT 请求,服务器会回复其 CONNACK 消息。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      DUP、QoS以及RETAIN标志在 CONNACK 消息中没有被使用到。

    • 可变头部(Variable header)

      可变头部的格式如下表所示。

      其中,连接返回码用1个无符合字节表示,具体含义如下表所示。

      如果客户端ID的长度不在1-23字节之间,服务器则会发送返回码2(标识符被拒绝)。

    • 有效载荷(Payload)

      该类型消息没有有效载荷。

    3.3 PUBLISH - 发布消息

    当客户端想发布消息给感兴趣的订阅者时,客户端将发送一条 PUBLISH 消息给服务器。每个 PUBLISH 消息都关联一个主题名(也可称为话题或频道)。主题名是一个层次性的空间,它将订阅者感兴趣的信息资源进行分类。一个主题的消息将会发送给连接时订阅了该主题的客户端。

    当客户端订阅了一个或多个主题,属于这些主题的所有消息都将通过服务器发送相应 PUBLISH 消息给客户端。

    译者注:其实流程简单来说就是,发布者客户端发送某topic的 PUBLISH 消息给服务器,然后服务器再发 PUBLISH 消息给所有该topic的订阅者客户端。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别设为1。详见交付质量级别和消息流。

      DUP标志设为0。表示该消息是第一次发送。详见DUP。

      RETAIN标志设为0。表示不保持。详见RETAIN。

      剩余长度字段长度包括可变头部和有效载荷。字段自身长度为1-4字节。

    • 可变头部(Variable header)

      可变头部包含以下字段:

      • 主题名

        一个UTF编码字符串。不允许出现主题通配符字符。

        客户端订阅主题时主题名可以使用通配符,但服务器最终给订阅客户端发布 PUBLISH 消息时,消息里的主题名是和发布者客户端发布的主题名一致的,也就是肯定不含有通配符。

      • 消息ID

        当消息的QoS级别为1或2时使用。详见消息标识符。

        下表是一个 PUBLISH 消息例子的可变头部。

        该头部的具体格式如下表所示。

    • 有效载荷(Payload)

      包含要发的消息的数据。数据的内容和格式由应用决定。固定头部中的剩余长度字段的值包括可变头部和有效载荷。当然,有限载荷长度为0的 PUBLISH 消息也是有效的。

    • 回复(Response)

      对PUBLISH 消息的回复取决于QoS级别。具体见下表。

    • 动作(Action)

      PUBLISH 消息可以由发布者客户端发给服务器,也可以由服务器发给订阅者客户端。PUBLISH 消息的接收者(包括服务器或客户端)根据消息的QoS级别做出不同的反应。

      QoS 0:仅仅将消息发送给所有相关的部分。

      QoS 1:将消息持久化存储,将消息发送给所有相关的部分,回复 PUBACK 消息给发送者。

      QoS 2:将消息持久化存储,先不将消息发送给所有相关的部分,而是先回复 PUBREC 消息给发送者。

      如果是服务器收到 PUBLISH 消息,则此时所有相关部分指的是订阅了该条 PUBLISH 消息主题的订阅者客户端。如果是订阅者客户端收到 PUBLISH 消息,则此时所有相关部分就是指客户端上等待服务器消息的各个应用。

      更多信息请参见交付质量级别和消息流。

      值得注意的是,如果一个服务器实现对某个客户端发送的一个 PUBLISH 消息不允许授权,它没有办法通知客户端。因此,当授权通过时,它需要做出一个正面的确认。根据正常的QoS规则,如果某个客户端没有发布 PUBLISH 消息的授权,这个客户端不会被告知。

    3.4 PUBACK - 发布确认

    PUBACK 消息是对QoS级别1的 PUBLISH 消息的回应。当发布者客户端发送 PUBLISH 消息给服务器,服务器有义务回复 PUBACK 消息。同样地,当服务器发送 PUBLISH 消息给订阅者客户端,客户端也有义务回复 PUBACK 消息。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,
      QoS级别未使用。

      DUP标志未使用。

      RETAIN标志未使用。

      剩余长度字段:因为没有有效载荷,所有长度为可变头部的长度(2字节)。

    • 可变头部(Variable header)

      包含被确认的 PUBLISH 消息的消息标识符(消息ID)。格式如下表所示。

    • 有效载荷(Payload)

      没有有效载荷

    • 动作(Action)

      当发布者客户端收到 PUBACK 消息,则它丢弃自己原先发送给服务器的 PUBLISH 消息,因为该消息已经被服务器接收并存储了。

    3.5 PUBREC - 发布接收(有保证的交付第1部分)

    PUBREC 消息是对QoS级别2的 PUBLISH 消息的回应。它是QoS级别2协议流中的第2个消息。PUBREC 消息可以是服务器对发布者客户端发送的 PUBLISH 消息的回应,也可以是订阅者客户端对服务器发送的 PUBLISH 消息的回应。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别未使用。

      DUP标志未使用。

      RETAIN标志未使用。

      剩余长度字段:因为没有有效载荷,所有长度为可变头部的长度(2字节)。

    • 可变头部(Variable header)

      包含被确认的 PUBLISH 消息的消息标识符(消息ID)。格式如下表所示。

    • 有效载荷(Payload)

      没有有效载荷

    • 动作(Action)

      当接收者收到 PUBREC 消息,则它将回复一个 PUBREL 消息,消息中携带的消息ID与收到的 PUBREC 消息中的相同。

    3.6 PUBREL - 发布释放(有保证的交付第2部分)

    PUBREL 消息可以是发布者客户端对服务器发送给它的 PUBREC 消息的回应,也可是服务器对订阅者客户端发送给它的 PUBREC 消息的回应。它是QoS级别2协议流中的第3个消息。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别设为1。PUBREL 消息使用QoS级别1,期望得到 PUBCOMP 消息回应。它的重传方式与 PUBLISH 消息一样。

      DUP标志设为0。表示该消息是第一次发送。详见DUP。

      RETAIN标志未使用。

      剩余长度字段:因为没有有效载荷,所有长度为可变头部的长度(2字节)。

    • 可变头部(Variable header)

      包含被确认的 PUBREC 消息的消息标识符(消息ID)。格式如下表所示。

    • 有效载荷(Payload)

      没有有效载荷

    • 动作(Action)

      当服务器收到发布者客户端发送的 PUBREL 消息,服务器会将之前收到 PUBLISH 消息发送给所有相关的订阅者,然后发送 PUBCOMP 消息给发布者客户端,其中携带的消息ID与客户端发送的 PUBLISH 消息ID相同。当订阅者客户端收到服务器发送的 PUBREL 消息后,客户端将消息发送给订阅的应用,然后发送 PUBCOMP 消息给服务器。

    3.7 PUBCOMP - 发布完成(有保证的交付第3部分)

    PUBCOMP 消息可以是服务器对发布者客户端发送给它的 PUBREL 消息的回应,也可以是订阅者客户端对服务器发送给它的 PUBREL 消息的回应。它是QoS级别2协议流中的第4个消息。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别未使用。

      DUP标志未使用。

      RETAIN标志未使用。

      剩余长度字段:因为没有有效载荷,所有长度为可变头部的长度(2字节)。

    • 可变头部(Variable header)

      包含被确认的 PUBREL 消息的消息标识符(消息ID)。格式如下表所示。

    • 有效载荷(Payload)

      没有有效载荷

    • 动作(Action)

      当发布者客户端收到 PUBCOMP 消息,它将丢弃自己原发发送的 PUBLISH 消息,因为该消息已经被正确地发送一次到服务器。

    3.8 SUBSCRIBE - 客户端订阅主题

    SUBSCRIBE 消息允许客户端向服务器订阅一个或多个感兴趣的主题。这些主题的发布消息都会通过PUBLISH 消息从服务器发送给客户端。SUBSCRIBE 消息还可以分别对各个主题指定客户端期望得到的QoS级别。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别SUBSCRIBE 消息使用QoS级别1来进行订阅请求。相应的 SUBACK 消息携带与之相同的消息ID。重传方式与 PUBLISH 消息相同。

      DUP标志设为0。表示该消息第一次被发送。详见DUP。

      RETAIN标志未使用。

      剩余长度字段长度包括可变头部和有效载荷(原文:The length of the payload)。字段自身长度为1-4字节。

    • 可变头部(Variable header)

      因为 SUBSCRIBE 消息使用QoS级别1,所以可变头部里包含有一个消息ID。详见消息标识符。

      下表是一个可变头部例子的格式。

    • 有效载荷(Payload)

      SUBSCRIBE 消息的有效载荷包括了一系列客户端想要订阅的主题,以及对各个主题,客户端期望接收消息的QoS级别。字符串经过UTF编码,指定的QoS级别虽然只用2bits表示,但仍要占用一个字节。主题字符串可以包含主题通配符来订阅一系列主题集。这些主题/QoS对的形式如下表中的例子所示。

      SUBSCRIBE消息里的主题名没有被压缩。

      上个例子的具体格式如下表所示。

      假设客户端订阅请求的QoS级别通过授权,该客户端之后收到的 PUBLISH 消息的QoS级别将等于或小于请求的QoS级别,这取决于消息发布者设定的消息QoS级别。例如,如果客户端申请订阅某主题的QoS级别为1,对于QoS级别为0的该主题的发布消息,该客户端只能以QoS级别0来接收。而对于QoS级别为2的该主题的发布消息,该客户端将降格以QoS级别1来接收。

      如果客户端以QoS级别2来订阅某主题,客户端相当于说:“我愿意以发布消息时设置的QoS级别来接收这个主题的消息。”。(译者注:因为级别2为最高级,发布消息不可能被降格。)

      这意味着,发布者有责任检测能被接收的最高QoS级别。不过,订阅者可以根据自己的需求来降格QoS级别。消息的QoS级别不可能被升格。

      请求的QoS字段跟随着每个UTF编码的主题名字符串之后,其格式如下表所示。

      当前版本协议中该字节的前6位未被使用,保留作将来使用。

      如果最后2位都被置位(即值为3),则应当将其视为非法包并关闭连接。

    • 回复(Response)

      当服务器收到来自客户端的 SUBSCRIBE 消息,应当回复一个 SUBACK 消息。

      在客户端收到服务器发送的 SUBACK 消息之前,服务器就可以向客户端的订阅发送 PUBLISH 消息。

      值得注意的是,如果一个服务器的实现不允许授权客户端的 SUBSCRIBE 请求,它没有办法告知客户端。因此,当授权通过时,它必须发送 SUBACK 消息来进行正面的回应。如果订阅没有通过授权,客户端不会被告知。

      服务器可以以低于客户端申请的QoS级别进行授权。当服务器没有办法提供高QoS级别时,这种情况就可能发生。例如,如果服务器不提供可靠的持久化存储,它可以选择只能QoS级别0来授权订阅。

    3.9 SUBACK - 订阅确认

    服务器通过发送 SUBACK 消息来确认其已收到 SUBSCRIBE 消息。

    SUBACK 消息包含一系列通过授权的QoS级别。它们的顺序与 SUBSCRIBE 消息里订阅的主题的顺序一致。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别未使用。

      DUP标志未使用。

      RETAIN标志未使用。

      剩余长度字段:长度包括可变头部和有效载荷(原文:The length of the payload)。字段自身长度为1-4字节。

    • 可变头部(Variable header)

      可变头部包含了确认的 SUBSCRIBE 消息的消息ID,格式如下表所示。

    • 有效载荷(Payload)

      有效载荷包含了一组通过授权的QoS级别。各个QoS级别对应 SUBSCRIBE 消息里的主题名。SUBACK 消息里QoS级别的顺序与 SUBSCRIBE 消息里申请的主题名/QoS对相匹配。可变头部里的消息ID可以让你匹配到对应的 SUBSCRIBE 消息。

      每个通过授权的QoS字段用一个字节来编码,如下表所示。

      当前版本协议中该字节的前6位未被使用,保留作将来使用。

      一个有效载荷的例子如下表所示。

      它的具体格式如下表所示。

    3.10 UNSUBSCRIBE - 客户端取消订阅主题

    客户端可以通过发送 UNSUBSCRIBE 消息给服务器来退订相应的主题。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别:UNSUBSCRIBE 消息使用QoS级别1来进行退订的申请。对应的 UNSUBACK 消息将用消息ID来识别。重传方式与 PUBLISH 消息相同。

      DUP标志设为0。表示该消息是第一次发送。详见DUP。

      RETAIN标志未使用。

      剩余长度字段长度包括可变头部和有效载荷(原文:This the length of the payload)。字段自身长度为1-4字节。

    • 可变头部(Variable header)

      因为 UNSUBSCRIBE 消息使用QoS级别1,所以可变头部里包含一个消息ID。详见消息标识符。

      下表是一个消息ID为10的可变头部例子的格式。

    • 有效载荷(Payload)

      有效载荷里包含客户端要退订的一系列主题名。这些字符串是UTF编码的,并且是连接的。UNSUBSCRIBE 消息里的主题名没有被压缩。一个有效载荷的例子如下表所示。

      它的具体格式如下表所示。

    • 回复(Response)

      服务器在收到客户端的 UNSUBSCRIBE 消息后,将回复 UNSUBACK 消息。

    3.11 UNSUBACK - 取消订阅确认

    服务器通过发送 UNSUBACK 消息来确认其已收到 UNSUBSCRIBE 消息。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,

      QoS级别未使用。

      DUP标志未使用。

      RETAIN标志未使用。

      剩余长度字段因为没有有效载荷,所有长度为可变头部的长度(2字节)。

    • 可变头部(Variable header)

      可变头部包含要确认的 UNSUBSCRIBE 消息的消息ID,它的格式如下表所示。

    • 有效载荷(Payload)

      没有有效载荷。

    3.12 PINGREQ - PING请求

    PINGREQ 消息从连接中的客户端发送给服务器,表示询问服务器:“你还活着吗”?

    更多信息参见保活计时器。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,DUP,QoS以及RETAIN标志未使用。

    • 可变头部(Variable header)

      没有可变头部

    • 有效载荷(Payload)

      没有有效载荷

    • 回复(Response)

      PINGREQ 消息的期望回复是 PINGRESP 消息。

    3.13 PINGRESP - PING回复

    PINGRESP 消息是服务器对客户端发送给它的 PINGREQ 消息的回应,表示回答客户端:“对,哥还活着”。

    更多信息参见保活计时器。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,DUP,QoS以及RETAIN标志未使用。

    • 可变头部(Variable header)

      没有可变头部。

    • 有效载荷(Payload)

      没有有效载荷

    3.14 DISCONNECT - 断开连接通知

    当客户端想要断开它的TCP/IP连接时,通过向服务器发送 DISCONNECT 消息告知服务器。这是为了干净地断开连接,而不仅仅是断开连线。

    如果客户端在连接时将clean session标志置位,则之前保持的客户端的信息将会被丢弃。

    服务器不应该仅仅依赖客户端发送的 DISCONNECT 消息来关闭TCP/IP连接。

    • 固定头部(Fixed header)

      固定头部的格式如下表所示。

      其中,DUP,QoS以及RETAIN标志未使用。

      可变头部(Variable header):没有可变头部。

      有效载荷(Payload):没有有效载荷。

    4. 消息流(Flows)

    4.1交付质量级别和消息流(Quality of Service levels and flows)

    MQTT 根据交付质量级别(QoS)来发送消息。所有级别描述如下所示:

    QoS 级别0: 至多交付一次

    消息依赖底层的TCP/IP网络做尽可能的发送。不要求响应且协议中也没有定义重传的语义。该消息要么只到达服务器1次,要么干脆一次也没有。

    QoS级别0的协议流如下表所示。

    QoS 级别1:至少交付一次

    服务器确认收到 PUBLISH 消息后要回复客户端一个 PUBACK 消息。不管是通信链路还是发送设备出现了故障,或是确认消息没有在规定时间内收到,则发送者(即之前发送 PUBLISH 消息的客户端)需要重发 PUBLISH 消息,且该消息头部中的DUP标志要置位。该消息将至少到达服务器一次。SUBSCRIBE 和 UNSUBSCRIBE 消息都需要使用QoS级别1。

    QoS级别1的消息头部里都包含有一个消息ID。

    QoS级别1的协议流如下表所示。

    如果客户端没有收到 PUBACK 消息(不管是超过应用设定的时间还是检测到故障然后通信会话重起),客户端将重发DUP标志被置位的 PUBLISH 消息。

    当服务器接收到一条客户端发来的重复消息,服务器仍然会将该重复消息发送给订阅者,然后再发送一条 PUBACK 消息给客户端。

    QoS 级别2:正好交付一次

    QoS级别2是在QoS级别1上更进一步的协议流,可以保证重复消息不会发送给接收端应用。这是最高级别的交付质量,用在重复消息不可接受的情况下。虽然使用该级别
    将带来网络流量的增长,但对于一些重要的消息内容这通常是可以接受的。

    QoS级别2的消息头部里都包含有一个消息ID。

    QoS级别2的协议流如下表所示。对于接收方有2种方式(语义)用来处理该 PUBLISH 流。这2种不同语义影响的是协议流中订阅者可以接收消息的时间点。这2种语义都可以保证QoS级别2的协议流,如何选择取决于具体的实现。

    如果检测到故障,或发生超时,协议流将重发最后一个未确认的协议消息,包括 PUBLISH 或 PUBREL。具体细节见消息重传。该级别中附加的协议流可以保证消息只交付给订阅者一次。

    QoS级别1和2的假设

    在任何网络中,设备或通信链路都有可能发生故障。发生故障时,链路的一端可能并不知道另一端发生了什么事,这被称为怀疑窗口(in doubt windows)。在这种背景下,对于消息发送,必须对设备和网络的可靠性作一个假设。

    MQTT假设客户端和服务器在一般情况下是可靠的,而通信通道更可能是不可靠的。如果客户端发生故障,则通常是灾难性的故障,而不大可能是暂时性的。从设备中恢复数据的可能性是很低的。有些设备具有非易失性存储,比如闪存ROM。为了应对各种可能的故障,需要提供更多的持久化存储来保护最重要的数据。

    除了最基本的通信链路的故障,更多超出MQTT处理能力的场景将使得故障模式矩阵显得更加复杂。

    4.2 消息重传

    尽管TCP通常可以保证数据包的送达,然而MQTT消息没有被收到的情况无疑是存在的。对于需要收到回应的MQTT消息(QoS>0,PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE),如果在规定时间内消息响应没收到,发送方将重发该消息,且该消息的DUP标志将被置位。

    重发超时应当是可配置的。超时的设置最好可以保证消息的正常传输不会引发超时。例如,通过一条拥挤的网络发送一条大消息的时间通常要长于通过一条快速的网络发送一条小消息的时间。一直重复地重传一条超时的消息将使情况变得更糟糕。因此,随着重传次数增加而增大超时的策略通常会被采用。

    当一个客户端重新连接时,如果Clean session标志没有被置位,则客户端和服务器双方都应当重发断线前正在传输中的消息。

    不同于上述“重连”重传行为,客户端不需要重发消息。然而,Brokers需要重发所有未确认的消息。

    4.3 消息排序

    消息的顺序会被一系列因素所影响,包括客户端允许同时在传的 PUBLISH 流的数量和客户端是单线程还是多线程的。为了讨论的简单,我们假设客户端在对网络中的数据包进行读写时是单线程的。

    对于一个提供有序消息保证的实现,它必须保证消息流的每个阶段的完成顺序都应该与它们的启动顺序保持一致。例如,对于一系列QoS级别2的消息流,它们发送 PUBREL 消息的顺序与它们发送 PUBISH 消息的顺序保持一致:

    客户端允许同时在传的消息数量(称为在传窗口)对保证交付的类型也有一定的影响:

    • 对于在传窗口为1的情况,每个消息流的开始都在上个消息流完成之后。这保证了消息的传送顺序与提交它们的顺序保持一致。
    • 当在传窗口大于1时,消息的有序化只能通过QoS级别来保证。

    附录 A

    主题通配符(Topic wildcards)

    斜线(/)是用来分隔一棵主题树里的各个层次,它提供了一个层次结构的主题空间。主题层次分隔符的引入为解决主题冲突有重要的意义。

    多层次通配符

    数字符号(#)即多层次通配符,用来匹配一个主题内的任意层次。例如,如果你想要订阅了 finance/stock/ibm/#,则你可以收到如下主题的消息:

    finance/stock/ibm
    finance/stock/ibm/closingprice
    finance/stock/ibm/currentprice
    

    多层次通配符可以表示0个或任意多个层次。因而, finance/# 也可以匹配单个 finance 主题,这时, # 代表0层次。当然,在这种情况下,多层次通配符的使用是没有意义的,因为根本没有层次需要分隔。
    多层次通配符只有2种用法,一是只有它自己本身,二是放在主题层次分隔符之后。因此, # 和 finance/# 都是合法的,而 finance#则是不合法的。多层次通配符在主题树使用时必须作为最后一个字符。例如, finance/# 是合法的,而 finance/#/closingprice 是不合法的。

    单层次通配符

    加号(+)是用来匹配一个主题层次的通配符。例如, finance/stock/+ 可以匹配 finance/stock/ibm 和 finance/stock/xyz ,但不能匹配 finance/stock/ibm/closingprice。同时,因为单层次通配符必须匹配一个层次,所以 finance/+ 不能匹配 finance 。
    单层次通配符可以用于主题树中的任意层次,而且可以与多层次通配符配合使用。与多层次通配符的用法一样,单层次通配符要么只有它自己,要么要放在主题层次分隔符之后。因而, + 和 finance/+ 都是合法的,而 finance+ 是不合法的。单层次分隔符即可以放在主题树的最后,也可以放在主题树的中间。例如, finance/+ 和 finance/+/ibm 都是合法的。

    主题语义和惯用法(Topic semantics and usage)

    当你在构建一个应用时,主题树的设计可以参考以下关于主题名语法和语义的设计原则:

    • 一个主题名必须不小于1个字符。
    • 主题名是大小写敏感的。例如, ACCOUNTS 和 Accounts 是两个不同的主题。
    • 主题名可以包含空格。例如, Accounts payable 应当是一个合法的主题名。
    • 以“/”开头的主题名和不以“/”开头的相同主题名是有区别的。例如, /finance 和 finance 是不同的, /finance 匹配于 +/+ 和 /+ , 但不匹配于 + 。
    • 不要在任何主题名中包含 `null` 字符(Unicode \x0000)。

    以下原则适用于主题树的构建和内容:

    • 长度被限制为64K,但主题树中的层次数量没有限制。
    • 可以有任意数量的根节点,也就是说,允许有任意数量的主题树。

    文档下载地址:
    http://download.csdn.net/detail/benhuo931115/9503572

    展开全文
  • 局域网设备发现之Bonjour协议

    万次阅读 多人点赞 2016-09-28 23:37:43
    WIFI物联网解决方案中,通常我们...它是一种基于服务的设备发现协议,不仅能够自动获取有效IP地址,还可以通过查询服务的方式来找到设备地址,只要双方约定好服务(service)的名称,设备的IP地址和端口都是可以变化的!

    WIFI物联网解决方案中,通常我们需要对设备进行绑定,需要通过某种方法先对设备进行发现,比如微信硬件采用广播的方式,定时向外发送上线消息或者采用一问一答的方式进行发现,Bonjour是由苹果公司实现的一种零配置网络(Zeroconf)协议,它是一种基于服务的设备发现协议,不仅能够自动获取有效IP地址,还可以通过查询服务的方式来找到设备地址,只要双方约定好服务(service)的名称,设备的IP地址和端口都是可以变化的!

     

    一、mDNS协议和DNS-SD协议

    Bonjour协议是基于mDNS(Multicast DNS)协议和DNS-SD(DNS Service Discovery)协议开发实现,因此有必要先在这里给大家介绍一下这两个协议。

    1.1 mDNS协议介绍

    mDNS协议适用于局域网内没有DNS服务器时的域名解析,设备通过组播的方式交互DNS记录来完成域名解析,约定的组播地址是:224.0.0.251,端口号是5353,mdns协议使用DNS协议一样的数据包,由头部和数据段两部分(大家可以自行去了解DNS数据包的格式啦,在这里不展开介绍了):

    mDNS的一个使用情景是这样的:

     
    设备d通过组播(224.0.0.251:5353),询问a.local地址是?
    设备a知道有人查询它后,也是通过同样的组播组回复它的地址信息(通过回复用于IPv4的A类型DNS记录(A Record)或者用于IPv6的AAAA类型的DNS记录,A记录和AAAA记录分别用于将域名转换成IP地址),这里组播内的所有人b, c, d都会收到,它们会将a.local的ip地址等信息(如TTL值)刷新到mDNS缓冲区中。
    mDNS协议和DNS协议还有些不同,mDNS只能用于局域网内部,并且它只接受解析主机名前缀为.local的域名,因此mDNS也是可以和DNS在同一台设备上共存的,以及它们存储记录的区域是分开的。
    除此之外,mDNS还有其它的作用,例如在零配置网络中给自己分配域名,设备给自身选择一个域名后,然后通过发送记录类型为”any”的mDNS包来查询局域网内是否有同名,如果没有设备就会把这个名字作为自己的域名。

    1.2 DNS-SD协议介绍
    接下来再介绍一下DNS-SD协议,即DNS based Service Discovery,基于DNS的服务发现主要用到DNS现有的三种类型记录(Record Type):PTR记录、SRV记录、TXT记录,其中:
    1)服务发现:设备会先发送一个查询PTR记录的数据包到组播组,所查询服务格式为:

    <service>.<transport>.<domain>
    service表示的是要查询的服务,transport表示的是传输的协议:TCP还是UDP,domain表示查询的域,在mDNS中为.local,接着具有对应服务的设备会响应一系列本设备上所具有的服务实例:
    <instance>.<service>.<transport>.<domain>
    instance表示服务的实例名,虽然收到<instance>.<service>.<transport>.<domain>,但是只有instance才会显示给用户看,比如:要查询一个_easylink._tcp.local的服务,具有这个服务对应实例的设备会响应一条PTR记录:EMW3031 Module#500A3F._easylink._tcp.local,即表示EMW3031 Module#500A3F为_easylink._tcp.local的一个实例,设备收到后只会显示EMW3031 Module#500A3F供用户看,它是UTF-8编码的。
    可以看出,DNS-SD的PTR记录所代表的意思是区别于传统DNS的PTR记录的含义的,并且DNS-SD下的PTR记录用于记录服务到服务实例的映射。

     

    2)获取服务实例的主机名和端口号:上述多个服务实例instance显示供用户选择确定一个后,就需要查询记录服务实例的主机名和端口号,即查询SRV记录。
    设备会发送一个mDNS请求,然后具有所请求中服务实例的设备会响应SRV记录,SRV记录记录了这个服务实例对应的主机名和端口号以及TTL信息,一条SRV记录的例子是:

    EMW3031 Module#500A3F._easylink._tcp.local. 3 IN SRV 0 0 8002 EMW3031 Module#500A3F.local.
    DNS下的SRV记录的格式为:
    _service._proto.name. TTL class SRV priority weight port target.
    在DNS-SD中,priority和weight无效,一般置为00 00,port和target即为端口号和主机名。
    因此SRV记录用于记录服务实例到端口号和主机名的映射,即便端口号可变也没有关系。

     

    3)服务实例更详细的信息:有时候,一个服务实例除了所在设备的端口号和主机名这些信息以外,还可以提供更多的附加参数信息,服务实例的附加信息记录在TXT记录中,以”key = value”的格式记录,如提供设备的MAC地址:

    MAC=D0:BA:E4:50:0A:3F

    二、Bonjour协议原理

    前面介绍了mDNS协议以及DNS-SD协议,其实基本上就已经展开介绍了Bonjour协议的细节,接下来再来理解Bonjour就相当轻松了。Bonjour协议可以理解为mDNS协议和DNS-SD协议的结合,其实大家在继续往下看之前可以自己想一下如何将两个协议结合起来呢?DNS-SD已经找到了提供服务的端口号和主机好了,最后再做进一步的主机名到IP地址的解析就完成了Bonjour协议的整个过程,当然结合的时候DNS-SD所发送的三种记录都是通过mDNS规定的组播组和端口号(224.0.0.254:5353)发送出去的,但是DNS-SD是不依赖mDNS协议而存在的。
    Bonjour协议提供三部分功能:通告服务、发现服务、解析服务,这是三个动宾词组哈。在物联网中,设备在本地记录一个服务往往需要提供服务相关的SRV记录、PTR记录以及TXT记录相关的信息,用于最后组装mDNS数据包发送出去。
    在没有DHCP分配IP地址和没有设置静态IP地址情况下,通过Bonjour协议还可以自己在局域网内获取有效的IP地址以及主机名,但是需要我们配置好路由的信息如子网掩码等,它会生成一个IP,然后询问局域网内是否有冲突,如果没有冲突就将这个IP占为己有,如果有冲突,就会更换一个IP,继续查询,主机名也是利用同样的方法获得。
    通告服务用于设备告之局域网内其他人本设备的服务信息,一般包括发送SRV记录和PTR记录,这些记录被其它mDNS设备记录在本地的存储区中。

    发现服务用于查询一个指定的服务,然后具有该服务的设备会响应PTR记录,告诉查询的设备有这样的服务并且服务实例的名称是什么。
    解析服务发生在完成服务发现之后,获得了服务实例后供用户选择,再下一步就要进行解析,首先根据服务实例获得该设备的主机名以及端口,最后再根据主机名来获取IP地址。
    经过以上一步步交互就可以获得了目标设备的IP地址和端口号了,然后就可以根据选择的传输协议TCP或者UDP进行通信。
    三、mDNS数据包
    庆科物联的设备端已经实现了Bonjour协议的主要功能,以下是基于其设备端发现过程用Wireshark抓的包,其中IP地址为192.168.191.2表示的是手机端,192.168.191.3表示的是完成配网后的设备端,它们在同一个局域网内。
    服务发现:由手机APP发送查询_easylink._tcp.local服务
    服务解析:设备端一次性响应了PTR记录、SRV记录、TXT记录以及A记录:
    每条记录展开为:
     

     

     

    展开全文
  • 物联网网络协议-MQTT协议使用

    千次阅读 多人点赞 2021-02-15 12:29:03
    物联网系统中网络协议是物联网设备之间沟通的“语言”,使用同一种语言,双方才能通信成功。MQTT 协议是最流行的一种,它甚至已经成为物联网系统事实上的网络协议标准。 第一步是安装 hbmqtt,它是一个开源的基于 ...
  • PC机与嵌入式设备通信协议设计原则

    千次阅读 2015-12-13 09:21:21
    PC机与嵌入式设备通信协议设计原则:简单,可扩展,低耦合,稳定,高效,易实现,软件开发和考虑硬件。
  • 计算机网络谢希仁第七版 课后答案

    万次阅读 多人点赞 2019-09-03 23:13:25
    这个协议就是很不科学的,因为任何一方如果有耽搁了而来不了,无法通知对方,而另一方必须一直等下去!所以看一个计算机网络是否正确,不能只看在正常情况下是否正确,而且还必须非常仔细的检查协议能否应付各种...
  • USB 协议分析(含基本协议和 USB 请求和设备枚举)

    万次阅读 多人点赞 2018-08-30 00:49:29
    目录 1. 物理特性 1.1 引脚 ...1.5 USB 设备检测 2. 通信协议 2.1 包组成(Packets Content) 2.1.1 PID 域 2.1.2 Address 地址域 2.1.3 Frame Number 帧号域 2.1.4 Data 数据域 2.1.5 C...
  • IPSec简介

    千次阅读 2018-06-10 11:53:39
    优点: 1.在网络层进行安全加密,便于公司和公司的信息传输的加密构建VPN 2.密钥协商的开销减少,只需要在公司出口的路由器上配置即可,不需要每个用户都做协商...有两个安全协议ESP协议和AH协议,在协议中涉及...
  • 文章目录物理层数据链路层网络层传输层会话层表示层应用层TCP/IP四层模型的关系 第一层到第七层: 物理层、数据链路层、网络层、传输层、会话层、表示层、...(设备有:网卡(同时工作在数据链路层)、网线、集线器
  • 计算机网络谢希仁第七版课后习题答案

    万次阅读 多人点赞 2019-10-12 21:43:44
    这个协议就是很不科学的,因为任何一方如果有耽搁了而来不了,无法通知对方,而另一方必须一直等下去!所以看一个计算机网络是否正确,不能只看在正常情况下是否正确,而且还必须非常仔细的检查协议能否应付各种...
  • 计算机网络谢希仁第七版 第二章 课后答案

    万次阅读 多人点赞 2019-07-03 23:04:12
    (1)物理层要尽可能地屏蔽掉物理设备和传输媒体,通信手段的不同,使数据链路层感觉不到这些差异,只考虑完成本层的协议和服务。(2)给其服务用户(数据链路层)在一条物理的传输媒体上传送和接收比特流(一般为...
  • 基础——IOT(物联网)的七大通信协议

    万次阅读 多人点赞 2019-09-30 10:31:04
    在物联网协议中,我们一般分为两大类,一类是传输...通信协议则主要是运行在传统互联网TCP/IP协议之上的设备通讯协议,负责设备通过互联网进行数据交换及通信。 ​ 上图为物联网联接的问题空间,其中物联网...
  • 首先介绍下背景。最近开始研究物联网的套件。... 主从式,主设备通过CAN总线与多台从设备相连,主设备室测量标定系统 ,从设备是需要标定的ECU,主设备首先与其中一个从设备建立逻辑连接,主、从设备之间的
  • 其网络的构成主要由电子设备系统和无线电系统构成,传输和处理的信号是模拟的。所以,“通讯”一词应特指采用电报、电话、网络等媒体传输系统实现上述媒体信息传输的过程。“通讯”重在内容形式,因此通讯...
  • GRE隧道协议

    万次阅读 多人点赞 2020-02-06 21:20:24
    1. GRE协议简介 GRE(General Routing Encapsulation ,通用路由封装)是对某些网络层协议(如IP和IPX)的数据报文进行封装,使这些被封装的报文能够在另一网络层... 机制简单,无需维持状态,对隧道两端设备的CPU负担...
  • 一看懂的IP协议!!!

    千次阅读 多人点赞 2021-07-29 00:00:23
    通信双方使用的IP协议的版本必须一致。目前广泛使用的IP协议版本号是4(即IPv4)。 首部长度:占4位,可表示的最大十进制数值是15。首部长度字段所表示的单位是32位字(1个32位字长位4字节)。因为IP首部的固定长度是20...
  • 交通部过检的808、809是车辆监控系统必须过检的功能,做车载的企业基本都围绕这两个协议做底层的封装,无非展示方式不同而已。对于一家做导航定位的企业,解析通信协议必须是最能够体现能力和耐心的一件事,必须了解...
  • OSPF协议

    千次阅读 2018-08-26 16:10:47
    是IETF开发的一种链路状态路由协议使用基于带宽的度量值。采用SPF算法计算路由,从算法上保证了无路由环路。通过邻居关系维护路由,避免定期更新对带宽进行的消耗。路由更新效率高,网络收敛快,适用大中型网络。 ...
  • 蓝牙4.0协议详解

    万次阅读 2018-07-31 14:52:59
    三、如何使用蓝牙4.0BLE协议栈 四、深入理解蓝牙4.0BLE协议协议栈概述 协议栈基础 详细介绍如下: 五、GATT定义了若干在GATT服务器和客户端之间的通信的子过程: 六、蓝牙4.0BLE协议栈分层思想的优点 一、...
  • 其网络的构成主要由电子设备系统和无线电系统构成,传输和处理的信号是模拟的。所以,“通讯”一词应特指采用电报、电话、网络等媒体传输系统实现上述媒体信息传输的过程。“通讯”重在内容形式,因此...
  • 常用物联网应用协议汇总

    千次阅读 2017-04-11 16:25:49
    原文发表自领英,转载已经作者授权 作者简介:席华彬,Siemens PLM Software 高级顾问 ...本文罗列下市面上物联网通信中的各类消息技术-即工作在网络通信的应用层协议,总结下它们各自特点、特...
  • AOA协议是Google公司推出的用于实现Android设备与外围设备之间USB通信的协议。 ADK中与USB配件模式相关的两个类是UsbManager和UsbAccessory。 > USB Android实战技巧之四十九:Usb通信之USB Host- ...
  • 网络协议篇之SNMP协议(一)——SNMP报文协议

    万次阅读 多人点赞 2017-08-12 19:45:02
    前言:最近工作中遇到大量的网络协议开发,现其中一些网络协议的基础知识进行整理,文中借鉴了一些大神的整理,后面会贴上链接,如侵删)
  • BLE协议栈详解

    千次阅读 2019-05-11 11:08:42
    所谓协议,即将指定的字节按照一定的顺序排列起来,以便他人使用自己的设备时,能通过该协议同其他设备进行通信。协议一特点,就是有固定的帧格式,通过该格式发送,接收者通过解读帧格式,进而得到新息内容; 3 ...
  • 深入理解网络协议,需要观察它们的工作过程并使用它们,即观察两个协议实体之间交换的报文序列,探究协议操作的细节,使协议实体执行某些动作,观察这些动作及其影响。
  • 网络协议极简总结

    万次阅读 多人点赞 2021-02-03 09:15:49
    4.1 MAC地址和IP地址 两台设备进行通讯的前提就是知道双方的地址,而IP地址和MAC地址都是地址,那么仅仅依靠IP地址或者MAC地址能否完成路由呢? 随着网络接入设备越来越多,为了解决寻址的问题,网络结构被层次化...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,818
精华内容 23,127
关键字:

双方就设备使用的协议