没有合适的资源?快使用搜索试试~ 我知道了~
MQTT协议笔记-打印版
4星 · 超过85%的资源 需积分: 47 37 下载量 186 浏览量
2015-09-02
14:17:40
上传
评论 4
收藏 772KB PDF 举报
温馨提示
试读
37页
MQTT协议笔记-打印版, 来自:聂永的博客 熟读此笔记, 基本上对MQTT协议会很熟悉! 7. MQTT 3.1.1,值得升级的6个新特性 nieyong 2014-12-16 6. MQTT 3.1协议非严肃反思录 nieyong 2014-12-12 10:19 5. MQTT协议笔记之订阅 nieyong 2014-04-12 16:03 4. MQTT协议笔记之消息流 nieyong 2014-02-15 19:17 3. MQTT协议笔记之发布流程 nieyong 2014-02-10 23:42 2. MQTT协议笔记之连接和心跳 nieyong 2014-02-09 13:41 1. MQTT协议笔记之头部信息 nieyong 2014-02-07 17:35
资源推荐
资源详情
资源评论
1/8
1. MQTT 协议笔记之头部信息
前言
MQTT(Message Queue Telemetry Transport),遥测传输协议,提供订阅/发布模式,更为简约、轻量,
易于使用,针对受限环境(带宽低、网络延迟高、网络通信不稳定),可以简单概括为物联网打造,官方
总结特点如下:
1.使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合。
2. 对负载内容屏蔽的消息传输。
3. 使用 TCP/IP 提供网络连接。
4. 有三种消息发布服务质量:
“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用
于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
“至少一次”,确保消息到达,但消息重复可能会发生。
“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢
失会导致不正确的结果。
5. 小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量。
6. 使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制。
MQTT 3.1 协议在线版本: http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html
官方下载地址: http://public.dhe.ibm.com/software/dw/webservices/ws-
mqtt/MQTT_V3.1_Protocol_Specific.pdf
PDF 版本,42 页,不算多。
另外,目前 MQTT 大家都用在了手机推送,可能还有很多的使用方式,有待进一步的探索。
协议方面,以前曾简单实现过一点 HTTP 协议,基于 HTTP 上构建若干种通信管道的 socket.io 协议,不过
socket.io 0.9 版本的协议才两三页而已。面对领域不同,自然解决的方式也不一样。
阅读完毕 MQTT 协议,有一个想法,其实可以基于 MQTT 协议,打造更加私有、精简(协议一些地方,
略显多余)的传输协议,比如一个字节的传输开销。有时间,会详细说一下。
2/8
固定头部
固定头部,使用两个字节,共 16 位:
bit 7 6 5 4 3 2 1 0
byte 1 Message Type DUP flag QoS level RETAIN
byte 2 Remaining Length
第一个字节(byte 1)
消息类型(4-7),使用 4 位二进制表示,可代表 16 种消息类型:
Mnemonic Enumeration Description
Reserved 0 Reserved
CONNECT 1 Client request to connect to Server
CONNACK 2 Connect Acknowledgment
PUBLISH 3 Publish message
PUBACK 4 Publish Acknowledgment
PUBREC 5 Publish Received (assured delivery part 1)
PUBREL 6 Publish Release (assured delivery part 2)
PUBCOMP 7 Publish Complete (assured delivery part 3)
SUBSCRIBE 8 Client Subscribe request
SUBACK 9 Subscribe Acknowledgment
UNSUBSCRIBE 10 Client Unsubscribe request
UNSUBACK 11 Unsubscribe Acknowledgment
PINGREQ 12 PING Request
PINGRESP 13 PING Response
DISCONNECT 14 Client is Disconnecting
Reserved 15 Reserved
除去 0 和 15 位置属于保留待用,共 14 种消息事件类型。
3/8
DUP flag(打开标志)
保证消息可靠传输,默认为 0,只占用一个字节,表示第一次发送。不能用于检测消息重复发送等。只适
用于客户端或服务器端尝试重发 PUBLISH, PUBREL, SUBSCRIBE 或 UNSUBSCRIBE消息,注意需要满足以
下条件:
当 QoS>0
消息需要回复确认
此时,在可变头部需要包含消息 ID。当值为 1 时,表示当前消息先前已经被传送过。
QoS(Quality of Service,服务质量)
使用两个二进制表示 PUBLISH 类型消息:
QoS value bit 2 bit 1 Description
0 0 0 至多一次 发完即丢弃 <=1
1 0 1 至少一次 需要确认回复 >=1
2 1 0 只有一次 需要确认回复 =1
3 1 1 待用,保留位置
RETAIN(保持)
仅针对 PUBLISH 消息。不同值,不同含义:
1:表示发送的消息需要一直持久保存(不受服务器重启影响),不但要发送给当前的订阅者,并且以后
新来的订阅了此 Topic name 的订阅者会马上得到推送。
备注:新来乍到的订阅者,只会取出最新的一个 RETAIN flag = 1 的消息推送。
0:仅仅为当前订阅者推送此消息。
假如服务器收到一个空消息体(zero-length payload)、RETAIN = 1、已存在 Topic name 的 PUBLISH 消
息,服务器可以删除掉对应的已被持久化的 PUBLISH 消息。
如何解析
因为 java 使用有符号(最高位为符号位)数据表示,byte 范围:-128-127。该字节的最高位(左边第一
位),可能为 1。若直接转换为 byte 类型,会出现负数,这是一个雷区。DataInputStream 提供了 int
readUnsignedByte()读取方式,请注意。下面演示了,如何从一个字节中,获取到所有定义的信息,同时
绕过雷区:
4/8
publicstaticvoidmain(String[]args){
bytepublishFixHeader=50;//00110010
doGetBit(publishFixHeader);
intori=224;//1110000,DISCONNECT,MessageType(14)
byteflag=(byte)ori;//有符号byte
doGetBit(flag);
doGetBit_v2(ori);
}
publicstaticvoiddoGetBit(byteflags){
booleanretain=(flags&1)>0;
intqosLevel=(flags&0x06)>>1;
booleandupFlag=(flags&8)>0;
intmessageType=(flags>>4)&0x0f;
System.out.format(
"Messagetype:%d,DUPflag:%s,QoSlevel:%d,RETAIN:%s\n",
messageType,dupFlag,qosLevel,retain);
}
publicstaticvoiddoGetBit_v2(intflags){
booleanretain=(flags&1)>0;
intqosLevel=(flags&0x06)>>1;
booleandupFlag=(flags&8)>0;
intmessageType=flags>>4;
System.out.format(
"Messagetype:%d,DUPflag:%s,QoSlevel:%d,RETAIN:%s\n",
messageType,dupFlag,qosLevel,retain);
}
处理 Remaining Length(剩余长度)
在当前消息中剩余的 byte(字节)数,包含可变头部和负荷(称之为内容/body,更为合适)。单个字节最大
值:01111111,16 进制:0x7F,10 进制为 127。单个字节为什么不能是 11111111(0xFF)呢?因为
MQTT 协议规定,第八位(最高位)若为 1,则表示还有后续字节存在。同时 MQTT 协议最多允许 4 个字
节表示剩余长度。那么最大长度为:0xFF,0xFF,0xFF,0x7F,二进制表示
为:11111111,11111111,11111111,01111111,十进制:268435455 byte=261120KB=256MB=0.25GB 四
个字节之间值的范围:
Digits From To
1 0 (0x00) 127 (0x7F)
2 128 (0x80, 0x01) 16 383 (0xFF, 0x7F)
3 16 384 (0x80, 0x80, 0x01) 2 097 151 (0xFF, 0xFF, 0x7F)
4 2 097 152 (0x80, 0x80, 0x80, 0x01) 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)
5/8
如何换算成十进制呢 ? 使用 java 语言表示如下:
publicstaticvoidmain(String[]args)throwsIOException{
// 模拟客户端写入
ByteArrayOutputStreamarrayOutputStream=newByteArrayOutputStream();
DataOutputStreamdataOutputStream=new
DataOutputStream(arrayOutputStream);
dataOutputStream.write(0xff);
dataOutputStream.write(0xff);
dataOutputStream.write(0xff);
dataOutputStream.write(0x7f);
InputStreamarrayInputStream=new
ByteArrayInputStream(arrayOutputStream.toByteArray());
// 模拟服务器/客户端解析
System.out.println("resultis"+bytes2Length(arrayInputStream));
}
/**
* 转化字节为 int 类型长度
*@paramin
*@return
*@throwsIOException
*/
privatestaticintbytes2Length(InputStreamin)throwsIOException{
intmultiplier=1;
intlength=0;
intdigit=0;
do{
digit=in.read();//一个字节的有符号或者无符号,转换转换为四个字节有符号 int
类型
length+=(digit&0x7f)*multiplier;
multiplier*=128;
}while((digit&0x80)!=0);
returnlength;
}
一般最后一个字节小于 127(01111111),和 0x80(10000000)进行&操作,最终结果都为 0,因此计
算会终止。代理中间件和请求者,中间传递的是字节流 Stream,自然要从流中读取,逐一解析出来。
剩余36页未读,继续阅读
资源评论
- klinsmann825222017-09-26非常有帮助,谢谢分享
zhwzju
- 粉丝: 15
- 资源: 16
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功