??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲免费视频一区二区,国产欧美精品一区,国产精品久久久久久模特http://www.aygfsteel.com/yongboy/category/54835.html记录工作/学习的点Ҏ滴?/description>zh-cnMon, 01 Jun 2015 03:42:48 GMTMon, 01 Jun 2015 03:42:48 GMT60MQTT-SN协议q之小l篇http://www.aygfsteel.com/yongboy/archive/2015/01/13/422207.htmlnieyongnieyongTue, 13 Jan 2015 09:15:00 GMThttp://www.aygfsteel.com/yongboy/archive/2015/01/13/422207.htmlhttp://www.aygfsteel.com/yongboy/comments/422207.htmlhttp://www.aygfsteel.com/yongboy/archive/2015/01/13/422207.html#Feedback6http://www.aygfsteel.com/yongboy/comments/commentRss/422207.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/422207.html

前言

q里单做一些小l和ҎQ针对前面的协议译部分Q一阶段的学习完l?/p>

MQTT-SN VS MQTT

MQTT-SNZMQTT原有语义Q但做了很多的调整。比如: 一个CONNECT消息被拆分ؓ3个消?主题名称需要用主题标识符替代 * |关地址可以q播、查询得?/p>

MQTT-SN ?MQTTҎQ用一张图介绍

比较cd MQTT MQTT-SN
传输cd 可靠点对Ҏ模式 不可靠的数据?/td>
通信方式 TCP/IP Non-IP ?UDP
|络传输 Ethernet, WiFi, 3G ZigBeeQBluetoothQRF
最消?/td> 2个字?/td> 2个字?/td>
最大消?/td> ≤24MB < 128个字?/td>
甉|供电 X
休眠支持 X
QoS -1(哑客L) X
主题标识W?/td> X
|关自动发现和回退 X

QoS

有关QoSQMQTT-SN新增增加了哑客户端(QoS Q?1Q支持:

QoS Level 消息传输ơ数 传输语义 传输保证
-1 ≤ 1 臛_一?/td> 无连接,只用于传输,力而ؓQ无保证Q只有MQTT-SN支持
0 ≤ 1 臛_一?/td> 力而ؓQ无保证
1 ≥ 1 臛_一?/td> 保证送达Q可能存在重?/td>
-1 ≡ 1 只有一?/td> 保证送达Qƈ且不存在重复

|关的查询和发现

  1. MQTT-SN客户端无L前知道网兛_址Q接收网关的周期性广播好了,或直接广播一条网x询;接收q播+d查询Q就够了
  2. MQTT-SN对客L/|关的ؕ入和丢失Q处理的很好Q备用网兛_ȝx掉之后即可{换ؓȝ养I针对客户端而言Q直接更C个新的网兛_址可?
  3. 存在的若q网兛_以互相协调彼此之间角Ԍ互ؓdstand-byQ出现问题,L下线l护Q从机升U主?

清理会话

和MQTT 3.1协议cMQ在上一ơ的客户端成功连接时在CONNECT中设|了清理会话标志clean session为falseQ遗q性Will也ؓtrueQ再ơ连接时Q那么服务器为其~存订阅数据和遗嘱数据是否已l被删除Q对客户端不透明Q因为就是服务器因内存压力{清理了~存Q但没有通知到客LQ会造成订阅、遗q误解?/p>

q好QMQTT-SN协议中,|关在清理掉遗嘱数据后,可以咨询客户端,或主动通知客户端断开Q重新徏立会话流E?/p>

在MQTT 3.1.1协议中,服务器会在CONNACK中标C话是否已l被持久的标记?/p>

主题标识W(Topic idQ?/h3>

切来说QMQTT-SN协议存在三种格式主题名称Qtopic nameQ,可由消息标志位包含TopicIdType属性决定:

  • 0b01Q预分配的主题标识符Qtopic idQ,16位自然数Q?-65535范围
  • 0b10Q预分配的短主题名称Qshort topic nameQ,只有两个字符表示
  • 0b00Q正怸题名Uͼtopic nameQ,可直接附加在REGISTER/SUBSCRIBE/WILLTOPICUPD消息对应字段?

所有主题被替换成标识符Q在发布PUBLISH消息Ӟ直接使用被指定的主题标识Wtopic id、short topic name卛_?/p>

MQTT-SN程梳理

下面对MQTT-SN常用程q行的流E简单梳理:

              Client              Gateway            Server/Broker
                |                   |                    |
Generic Process | --- SERCHGW ----> |                    |
                | <-- GWINFO  ----- |                    |
                | --- CONNECT ----> |                    |
                | <--WILLTOPICREQ-- |                    |
                | --- WILLTOPIC --> |                    |
                | <-- WILLMSGREQ -- |                    |
                | --- WILLMSG ----> | ---- CONNECT ----> |(accepted)
                | <-- CONNACK ----- | <--- CONNACK ----- |
                | --- PUBLISH ----> |                    |
                | <-- PUBACK  ----- | (invalid TopicId)  |
                | --- REGISTER ---> |                    |
                | <-- REGACK  ----- |                    |
                | --- PUBLISH ----> | ---- PUBLISH ----> |(accepted)
                | <-- PUBACK  ----- | <---- PUBACK ----- |
                |                   |                    |
                //                  //                   //
                |                   |                    |
 SUBSCRIBE   -->| --- SUBSCRIBE --> | ---- SUBSCRIBE --> |
 [var Callback] | <-- SUBACK ------ | <--- SUBACK ------ |
                |                   |                    |
                //                  //                   //
                |                   |                    |
                | <-- REGISTER ---- | <--- PUBLISH ----- |<-- PUBLISH
                | --- REGACK  ----> |                    |
[exec Callback] | <-- PUBLISH  ---- |                    |
                | --- PUBACK   ---> | ---- PUBACK  ----> |--> PUBACK
                |                   |                    |
                //                  //                   //
                |                   |                    |
active -> asleep| --- DISCONNECT -> | (with duration)    |
                | <-- DISCONNECT -- | (without duration) |
                |                   |                    |
                //                  //                   //
                |                   |                    |
                |                   | <--- PUBLISH ----- |<-- PUBLISH
                |                   | ----- PUBACK ----> |
                |                   | <--- PUBLISH ----- |<-- PUBLISH
                |                   | ----- PUBACK ----> |
                |                   | (buffered messages)|
asleep -> awake |                   |                    |
                | --- PINGREQ ----> |                    |
awake state     | <-- PUBLISH  ---- |                    |
                | <-- PUBLISH  ---- |                    |
                | <-- PINGRESP ---- |                    |
asleep <-awake  |                   |                    |

MQTT-SNq行的协议栈

MQTT-SN可以q行在不同的无线协议上,只要可以满MQTT-SN 所定义卛_Q支持双向数据传输和|关卛_QMQTT-SN完全可以q行在其上面?/p>

MQTT-SN可以在ZigBee、Bluetooth、RF、UDP?loWPAN{底层协议层面运行?/p>

MQTT-SN|络拓扑?/h3>

下面是来自网友的ZMQTT-SNq行的架构图Q?/p>

但实际上的其|络拓扑可能更ؓ复杂Q比如两个不同的传感器网l:

传感器和制动器,合称为SA。传感器汇报状态数|自n发布PUBLISH消息Q,制动器会被某参数D发(接收到的PUBLISH消息Q。好比,文g的输?输出模式Q传感器用于文g的读取,制动器用于文件写入。或者用管道阀门,某指标超q阀D发制动器报警QSA一起作用便于更好追t数据。大部分旉QPUBLISH消息被用于触发制动器Q这建立在后端服务器的分析结果基上?/p>

MQTT-SN比较知名的实玎ͼ比如(http://eclipse.org/proposals/technology.mosquitto/)[Eclipse Mosquitto]Q?RMSB)[http://git.eclipse.org/c/mosquitto/org.eclipse.mosquitto.rsmb.git/]{,但不是实现所有已定义l节Q比如MQTT-SN协议转发部分(MQTT-SN Forwarder)Q就鲜有实现Q但实现不难嘛,可能~Z相应的场景支持吧?/p>

MQTT-SN支持cM于传感器的网养IE强的网l可与适用于MQTT协议Q这L来,MQTT要做到连接一切(Connect anythingQ,如IBM所发布的红皮书所_要用MQTT打造一个智能星球,有戏Q?/p>

nieyong 2015-01-13 17:15 发表评论
]]>
MQTT-SN协议q之实现要?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/01/11/422172.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Sun, 11 Jan 2015 04:08:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/01/11/422172.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/422172.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/01/11/422172.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/422172.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/422172.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"> <h3 id="-">前言</h3> <p>本篇是MQTT-SN 1.2协议最后一翻译了Q主要涉及实现要点,很简短?/p> <h3 id="-qos-1">需要支持QoS gؓ -1</h3> <p>QoS虽默认设|有0,1,2三个|但还有一U情况其gؓ-1。来自客L的PUBLISH消息中若QoS?1的情况下Q此dL不会兛_和网x没有建立q接Q也不在乎时间点Q有消息需要发出去。透明的网关需要维护此cL息ƈ与远E的MQTT Server建立一个专用TCPq接。聚合网xhybirdh|关可用已有的MQTT Serverq接转发此类消息?/p> <h3 id="-">定时器和计时器实践徏?/h3> <table> <thead> <tr> <th>定时?计数?/th> <th>说明</th> <th>推荐?/th></tr></thead> <tbody> <tr> <td>T_ADV</td> <td>q播频率</td> <td>大于15分钟</td></tr> <tr> <td>N_ADV</td> <td>没有接收到ADVERSEq播ơ数</td> <td>2-3?/td></tr> <tr> <td>T_SEARCHGW</td> <td>发送SEARCHGW延迟</td> <td>5U?/td></tr> <tr> <td>T_GWINFO</td> <td>{待|关响应GWINFOq播延迟旉</td> <td>5U?/td></tr> <tr> <td>T_WAIT</td> <td>{待旉</td> <td>大于5分钟</td></tr> <tr> <td>T_RETRY</td> <td>重试旉</td> <td>10s - 15s</td></tr> <tr> <td>N_RETRY</td> <td>重试ơ数</td> <td>3-5?/td></tr></tbody></table> <p>|关处理客户端的休眠和存zd时器Q需要根据客L在所发送消息中延箋旉的定义倹{例如,定时器值应该高?0%大于指定值持l时?分钟Q如果不高出50%?/p> <h4 id="-topic-id-topic-name-">|关持有的Topic Id和Topic Name的映维?/h4> <p>协议严重所有客L的Topic Id和Topic Name之间对应关系不应该用一个共享池对象Q因样可以避免不同客LTopic Id和Topic Name匚w错误Q将PUBLISH消息发错地方Q客L接收者)Q可能会D引发潜在的不可恢复的N性后果?/p> <p>正确做法是按照客L的维度ؓl护Topic Id和Topic Name的对应关pRQ何两个客L之间可能会存在同LTopic NameQ但对应的Topic Id不一栗可能Topic Id一_但Topic Name不一栗?/p> <h3 id="zigbee-">ZigBee 相关问题</h3> <ul> <li>在ZigBee规范中,|关需要被托管在一个协调器节点内,MQTT-SN协议|关更应该而驻留在一个不间断q行的的ZigBee路由器节点上Q能够随时接收来自客L消息? </li><li>受限于ZigBee|络支持层有限的数据负蝲定wQMQTT-SN消息最大负载被限制?0字节?</li></ul> <h3 id="-">结</h3> <p>MQTT-SN 1.2协议到此译Q非直译Q完毕,嗯,有种惌吐血的感觉,但也是坚持了下来 (^_^)?/p> <blockquote> <p>我的生一片无悔,我想起那天夕阳下的奔跑,那是我逝去的青春?br />---《万万没惛_》王大锤</p></blockquote></div><img src ="http://www.aygfsteel.com/yongboy/aggbug/422172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-01-11 12:08 <a href="http://www.aygfsteel.com/yongboy/archive/2015/01/11/422172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT-SN协议q之功能描q?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/01/09/422156.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 09 Jan 2015 09:32:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/01/09/422156.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/422156.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/01/09/422156.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/422156.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/422156.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"> <h3 id="-">前言</h3> <p>紧接上文Q这是第三篇Q主要是对MQTT-SN 1.2协议q行M性功能描q?/p> <p>嗯,q一部分可以l合着MQTT协议Ҏ着来看?/p> <h3 id="-">|关的广播和发现</h3> <p>|关只能在成功连接到MQTT Server之后Q才能够周期性的在无U个人区域网WPNs内对所有客Lq播ADVERTISE消息Q便于客L被动知道|关的存在?/p> <p>在同一|络下,多个拥有不同Id的网兛_有同时运行中Q但会由客户端根据信号强弱决定连接具体网养I无论何时只能q接一个网兟?/p> <p>客户端可l护一份可用网兛_表(包含|关地址Q,在接收到包含有新的网关id的ADVERTISE和GWINFO消息后,其列表需要添加新的网兛_素进厅R?/p> <p>ADVERTISEq播消息包含的下一ơ广播间隔时长Duration属性,单位U,设ؓ变量T_ADVQ应该尽可能大与15分钟Q?00U)Q频率降低是Z避免低速个人区域网l的拥塞?/p> <p>针对接收ADVERTISE消息频率Q处理能力较强客L可以用于监督|关是否可用。egQ客Lq箋N_ADVơ接收不到某个网关ADVERTISEq播消息Q可认ؓ此网关经L不可用ƈ且从已维护的|关列表中移除。同LQ作为备用的|关认ؓȝ兛_挂掉Q此时可处于Ȁzȝ态,正常发挥作用?/p> <p>|关发送广播消息ADVERTISE的时间间隔很长,q对D新加入的客户端不利,但客L可以直接发送SEARCHGWq播消息q行查询|关。大量的新入讑֤会造成q播风暴造成|络拥挤Q每一个新加入的客L在发送SEARCHGWq播消息之前都需要获取一个随机的延迟发送?0-Tsearchgw)Q在延迟{待发送期间若接收到其它客L发送的SEARCHGWq播消息Q会取消掉自qSEARCHGWq播消息发送,{待|关GWINFO消息通知?/p> <p>SEARCHGW消息属性radiusq播半径Q记为变量RbQ?跻I1 hopQ在一般密集部|下的MQTT-SN客户端基本可用?/p> <p>|关接收到SEARCHGW会即d复包含自wid的GWINFO消息。客L收到SEARCHGW后,若有需要gq发送的SEARCHGW会取消掉Q若自nl护一份多个可用网兛_表,在等待T_GWINFO旉内没有收到GWINFO消息Q会从列表中取出一条网关信息组装成GWINFO消息q广播出厅R这p求客L已运行多Ӟq且l护多个可用|关列表?/p> <p>GWINFO和SEARCHGW所包含半径radius属性g_q就要求底层|络在传输时q行军_是否需要传输到其它cd|络中?/p> <p>若没有接收到响应QSEARCHGW消息可能被重C输。两个连l的SEARCHGW消息重传间隔应该呈指数Ş式增加,避免太密集传输?/p> <h3 id="-">客户端的q接建立</h3> <p>无论是基于哪一U传输协议,TCP or UDPQ客L都需要徏立连接,q且保持心蟩Q逻辑上和服务器端保持一条不断线的双向通道。下面一张图Q演CZ客户端徏立连接的q程Qƈ且设定客L在CONNECT消息中标志位字段中遗嘱WILL属性ؓtrueQ然后就有了遗嘱主题/消息的请求过E?/p> <p><img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/mqtt-sn-03.jpg" /></p> <p>很多情况下,q接CONNECT是不需要遗嘱支持的Q网关会直接q回CONNACK消息Q但|关会因为拥塞或不支持一些CONNETҎ,CONNACK所包含q回代码字段ReturnCode中包含拒l代码,要求客户端检查是否连接成功,区别对待。比如:</p><pre><code> <span id="wmqeeuq" class="hljs-attribute">CONNACK消息q回状态码?x01QRejected</span>: <span id="wmqeeuq" class="hljs-string">congestionQ因拥塞被拒l)Q客L需要在T_WAIT旉间隔后进行重试?/span> </code></pre> <h3 id="-">回话清理</h3> <p>已经q接的客L断线后,若之前在CONNECT中没有设|过会话清理QClean SessionQ标识,那么之前的订阅等信息在网兛_会持久存在。相比MQTTQMQTT-SN中的“Clean Session”标识被扩展到遗嘱Ҏ中。在CONNECT消息中,CleanSession和Willl合会产生以下效果Q?/p> <ul> <li><strong>CleanSession=true, Will=true</strong>: |关会删除之前对应的所有订阅和遗嘱Q新的遗׃?消息E后卛_重新处理 </li><li><strong>CleanSession=true, Will=false</strong>: |关会删除之前对应的所有订阅和遗嘱Q返回CONNACK消息 </li><li><strong>CleanSession=false, Will=true</strong>: |关l持有之前对应的所有订阅,新的遗嘱主题/消息E后卛_重新处理 </li><li><strong>CleanSession=false, Will=false</strong>: |关会l箋持有之前对应的所有订阅和遗嘱{数据,q返回CONNACK消息 </li></ul> <h3 id="-">更新遗嘱程</h3> <ul> <li>CONNEECTION中标志位Will中设|是否需要更新遗׃?消息 </li><li>IWILLTOPICQ两个字节)消息会促ɾ|关删除对应遗嘱数据 </li><li>WILLTOPICUPD/WILLMSGUPD可以更新/修改遗嘱主题、遗嘱消? </li><li>I白WILLTOPICUPDQ两个字节)消息意味着h|清I对应已有的遗嘱数据 </li></ul> <h3 id="-">主题注册程</h3> <p>受限于无U传感器|络的有限带宽和微小消息负蝲QPUBLISH消息中不能够包含完整的主题名Utopic name。这需要客L和网关之间通过注册程Q获取主题名U对应的Q?6位的自然敎ͼtopic idQ然后塞入PUBLISH消息的topicId属性中?/p> <p>客户端发送REGISTER消息Q网兌回REGACK消息Q其所包含的ReturenCode属性决定注册成功与否:</p> <ul> <li>ReturnCode = “accepted”QtopicId可以很愉快的使用在稍后的PUBLISH消息? </li><li>ReturnCode = “rejected: congestion”Q客L需要稍{一D|_T_WAIT表示Q大?分钟Q再ơ重新注? </li><li>ReturnCode = “rejected: invalid topic ID/not supported”Q客L需要稍作调_再次重新注册 </li></ul> <p>L旉Q只能执行一个REGISTER消息Q有没有完成注册程Q需要等待?/p> <p>|关->客户端方向,|关发送REGISTER消息l通知客户端指定topicId对应某个主题Q以便后面发送PUBLISH消息使用。若客户端在订阅SUBSCRIBE消息时用了通配W(#/+Q,那么与之相匹配的topic name也将被一一通知到。因此不使用通配W,较ؓ低效?/p> <h3 id="-">客户端发布流E?/h3> <p>客户端一旦获取到topic name对应topic idQ就可以直接发送PUBLISH消息了。这和MQTT协议相比QPUBLISH消息中Topic Name被替换成Topic IdQ除此之外,q要注意ReturnCodeQ?/p> <ul> <li>ReturnCode = “rejected: congestion”Q客L需要稍{一D|_>5分钟Q后再次重试 </li><li>ReturnCode = “rejected: invalid topic ID”Q客L需要重新注册topic name获取topic idQ然后再ơ重新发?</li></ul> <p>QoS 1?QoS 2在Q一旉Q都必须{待已有PUBLISH消息完成Q才能进行下面的PUBLISH消息发布程?/p> <h3 id="-topic-id-topic-name">预定义topic id和两个字W的topic name</h3> <p>预定义的topic id已提前指z֥对应的topic nameQ需要客L和网兛_代码层支持Q省略了中间注册程Q在q接建立之后可以马上q行PUBLISH消息Q但q需要在PUBLISH标志Flags字段中设|TopicIdTypegؓ0b01Q?b10表示两个字节长度的短topic nameQ。虽然可以快速发送PUBLISH消息Q但客户端想订阅预定义的topic idQ接收对应的PUBLISH消息Q一样需要发送SUBSCRIBLE消息hq行订阅。若乱指定预定义topic idQ会收到ReturnCode=“Rejection: invalid topic Id”的异常?/p> <p>预定义的短topic name只有两个字符长度的字W串Q也是两个字节)Qtopic idZ个字节表C的一个自然数Q?-65535Q,两者用场景一_都需要在标志位Flags讄TopicIdType具体|0b01表示预定义topic idQ?b10表示两个字节长度的短topic nameQ需要分清?/p> <h3 id="publish-qos-1-">PUBLISH对应QoS -1?/h3> <p>q对仅仅支持PUBLISH QoS -1的非常简单的客户端实现而言Q除此之外不支持MҎ。它不关心连接是否徏立,也没有注册、订阅这一_按照已经固化C码中的网兛_址直接发送PUBLISH消息Q不兛_|关地址是否正确、网x否存zR消息是否发送成功?/p> <p>下面的PUBLISH属性g赖于QoS -1的情况:</p> <ul> <li>QoS标志Q被|ؓ0b11 </li><li>TopicIdType标志Q可能是Q预定义topic idQ?b01也可能是Q短topic nameQ?b10 </li><li>TopicId字段Q预定义topic id或短topic name </li><li>Data字段Q需要发送的数据Q没啥变?</li></ul> <h3 id="-">客户端的订阅和退?/h3> <p>客户端对某个主题感兴,可以发vSUBSCRIBLE程Q携带上感兴的主题名(topic idQ,服务器一般会q回包含有指定主题IdQtopic idQ的SUBACK消息。订阅失败,可以从PUBACK的ReturnCode中获知:</p> <ul> <li>ReturnCode = “rejected: congestion”Q客L需要稍{一D|间T_WAITQ?gt;5分钟Q后再次重试 </li></ul> <p>有一U情冉|SUBSCRIBLE订阅主题包含通配W,|关的处理就很简单,在SUBACK中返回的topic id?x0000。稍后,|关向客L发送REGISTER消息走注册流E,通知通配W匹配到的主题对应的topic id倹{?/p> <p>来自客户端的SUBSCRIBLE消息一h持预定义topic idQ以及短topic nameQ这和PUBLISH消息差不多?/p> <p>退订就很简单,客户端发送UNSUBSCRIBLE消息Q网兌回UNSUBACK消息?/p> <p>但同一时刻Q客L只允许处理订阅SUBSCRIBLE或取消订阅UNSUBSCRIBLE按照串行化顺序,下一个操作依赖于上一个操作完全成功?/p> <h3 id="-">|关发布程</h3> <p>服务器发布流E和客户端类|在发布之前需要检其主题是否已经向客L提前注册q,若无需要把主题和指定的topic id攑օREGISTER消息中发送给客户端进行注册流E,然后{待客户端处理结果REGACK。注册通过Q然后才能正常发送PUBLISH消息?/p> <p>|关需要确保REGISTER的主题以及PUBLISH消息的内容负载都不能太长过当前|络负蝲上限Q比如在ZigBee环境下不能超q?0个字节)Q取消注?发布程好了?/p> <p>|关发布PUBLISH消息Ӟ客户端检到未知的topic idQ把拒绝理由装到PUBACK后,|关遇到ReturnCode=“Rejected: invalid Topic ID”非法topic idQ需要考虑删除或重新注册?/p> <p>客户端或怼拒绝其注册,或许会不允许PUBLISH消息Q网兛_上静默处理就好了Q失败就p|了,不需要告知别人?/p> <p>客户端发布流E于此类|需要在发布之前q行主题注册以获取指定的topic idQ提交PUBLISH消息后,同样需要检查PUBACK所包含的ReturnCode字段是接受还是拒l,因网l拥塞而生的拒绝Q客L需要在T_WAIT旉后再ơ重试?/p> <p>客户端的发布必须是串行方式,下一个需要发送到PUBLISH消息需要等待上一个发送成功被|关接受之后才能q行处理?/p> <h3 id="-">心蟩保活程</h3> <p>一般是客户?>|关Q网?>客户端也没有问题。但要求PINGREQ -> PINGRESP 一定要单个旉循环QPINGREQ发送者不能也是PINGRESP的发送者,那样不但׃程Q也费了网l资源。嗯Q不允许双向互发?/p> <p>客户端可Z心蟩机制监测已连接网兛_康与否,q箋多次接收不到来自|关的PINGRESP消息后,客户端连接下一个可替换的网兟뀂因为客L的连接和心蟩和其它客L状态属性不同步Q但q可能会带来一个问题,同一旉若有大量的客Lz水般同时连接一个网养I|关可能毫无征兆的会被冲垮掉。这p求网兌有批量的q接处理能力Qƈ发特性增强才行?/p> <h3 id="-">客户端断U流E?/h3> <p>客户端主动发送DISCONNECT消息告知|关需要断U之后,若有交换信息的需要可以重新发起一个新的会话连接。DISCONNECT消息之后Q网关不会清理掉已有订阅和遗嘱数据,除非在之前的CONNECT消息中已性设|了CleanSession会话清理标识为true。网x收到DISCONNECT消息之后会返回一个DISCONNECT消息作ؓ响应?/p> <p>有一U情冉|客户端会H然接收到来自网关的DISCONNECT消息Q这也许是网兌w发生了异常错误Q或|关无法定位客户端的消息归属Q客L的消息和客户端无法关联到一PQ此时客L需要发送CONNECT消息重徏与网关的会话q接?/p> <h3 id="-">客户端重传流E?/h3> <p>客户?>|关的消息都是单路传播的Q这依赖于客L所持有的已q接|关的单播地址?/p> <p>客户端发送一个消息之后,需要启动一个重试定时器Tretry和一个重试计数器Nretry用以监督|关消息响应。定时器会被客户端在指定旉内接收到来自|关的消息后取消掉,若没有准时接收到则会触发定时器执行消息重发流E,q箋Nretryơ重发后Q客L会直接取消掉当前程Q判断当前网兛_l断U,需要连接到另外一个可用的|关。假如另外的|关也是q接p|Q会试重连之前的网兟?/p> <p>若在休眠状态下Q一旦超q重试计数器|客户端直接进入休眠状态?/p> <h3 id="-">客户端休眠支持策?/h3> <p>q里所说的客户端指的是依赖甉|驱动的电子设备,你要明白一个事实,节省甉|资源是多麽的重要Q省电就是关键,没电了就没得玩了嘛。当不处于激zȝ态时Z省电得需要进入睡?休眠状态,当有数据需要接收或发送时可以醒q来。网兛_需要追t设备的休眠状态ƈ且支持缓存需要发送给休眠讑֤的消息,在设备唤醒时一一发送?/p> <p>下面是客L的状态{换图Q很清晰描述了各U状态之间的交互Q?<img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/mqtt-sn-04.jpg" /></p> <p>客户端具有五U状态:Ȁz(activeQ,休眠QasleepQ,唤醒QawakeQ,断线QdisconnectedQ,丢失QlostQ,每次只能是其中一U?/p> <p>|关需要监督客L的状态,开始于CONNECT消息中存zL长字D(keep aliveQ,在大于存zL长时间内|关接收不到来自客户端消息,|关认ؓ客户端已l处于丢q态(lostQ,会激zd应的遗嘱Ҏ若存在的话?/p> <p>客户端发送DISCONNECT消息但没有duration休眠旉字段Q网兌处于没有时间监督的断线状态。一旦包含duration休眠旉字段Q表C客L需要休眠一D|_|关q客L被{换ؓ休眠状态,休眠旉为duration所定义在倹{超q此休眠旉的一D|间内Q网兌接收不到客户端发送过来的M消息Q那么客L会被转化Zq态,若已讄遗嘱Ҏ,此时遗嘱Ҏ会生效。客L休眠期间需要被发送的消息都会被网关缓存?/p> <p>睡眠状态下程图会更Ş象的说明程Q?<img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/mqtt-sn-05.jpg" /></p> <p>毫无疑问Q网兛_使用一个休眠定时器l护客户端的休眠状态等Q休眠定时器会被停掉当网x收到客户端发送过的PINGREQ消息Q网关从PINGREQ消息所包含的Client Id索是否存在已~存的PUBLISH消息Q若有会一一按照序发送到客户端。所有对应已~存消息发送完毕后Q会随之发送一个PINGRESP消息。若没有~存消息Q网关直接返回一个PINGRESP消息。网关会重新启动休眠定时器,|关l护的客L状态被转换Z眠状态,客户端在接收到PINGRESP消息之后Q将直接转向休眠状态,节省用电?/p> <p>客户端在唤醒状态下处理消息Q遵?#8220;客户端重传流E?#8221;行ؓQ一旦达到重试计数器限制Q将q入睡眠状态?/p> <p>客户端从休眠状态{向唤醒状态用于检查网x否ؓ其缓存消息时Q需要发送一个PINGREQ消息到网养I从休?唤醒状态{换ؓȀzȝ态,需要发送一个CONNECT消息告知|关Q{换ؓ断线状态时需要发送两个字节的DISCONNECTQ没有休眠时长字DdurationQ消息;需要重新定义的休眠旉Q发送一个DISCONNECT消息Q包含新的duration旉|通知|关卛_?/p> <h3 id="-">结</h3> <p>功能性描qCl完了,基本上MQTT-SN协议介绍已接q尾壎ͼ最后面的篇章就是短短的实现描述了?/p></div><img src ="http://www.aygfsteel.com/yongboy/aggbug/422156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-01-09 17:32 <a href="http://www.aygfsteel.com/yongboy/archive/2015/01/09/422156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT-SN协议q之消息格?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/01/08/422142.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 08 Jan 2015 13:52:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/01/08/422142.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/422142.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/01/08/422142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/422142.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/422142.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"> <h3 id="-">前言</h3> <p>紧接着上篇初步介绍Q本文ؓW二,主要梳理MQTT-SN 1.2协议中定义的消息格式?/p> <h3 id="-">通用消息格式</h3> <table> <thead> <tr> <th style="text-align: left">消息?/th> <th style="text-align: left">其它可变部分</th></tr></thead> <tbody> <tr> <td style="text-align: left">2/4字节表示</td> <td style="text-align: left">N字节l成</td></tr></tbody></table> <h3 id="-">消息头部</h3> <table> <thead> <tr> <th>长度</th> <th>消息cd</th></tr></thead> <tbody> <tr> <td>1?个字?/td> <td>1个字?/td></tr></tbody></table> <ul> <li>长度要么?个字节,要么3个字节表C,q且自n也会包含在其内。一个字节可表示256长度Q一般情况下Q完全够用了? </li><li>只需要判断第一个字节是否ؓ <strong>0x01</strong>Q若是那么长度ؓ3个字节表C,剩下的两个字节会表示真正的消息长度,最大长度ؓ65535 </li><li>否则长度是一个字节表C,256个长度,大部分消息长度都是一个字节,除非特别提醒 </li></ul> <p>备注Q?/p><pre><code> MQTT-SN不支持消息的分片和重l。底层网l所定义数据包长度若于MQTT-SN消息的最大长度,自nq行的分片和重组Q对MQTT-SN协议本n不受影响? </code></pre> <h4 id="mqtt-sn-">MQTT-SN消息cd</h4> <p>MQTT-SN定义的消息类型数量众多,过25个,感觉有些头大?/p> <table> <thead> <tr> <th>消息cd?/th> <th style="text-align: left">消息cd名称</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0x00</td> <td style="text-align: left">ADVERTISE</td> <td style="text-align: left">q播消息</td></tr> <tr> <td>0x01</td> <td style="text-align: left">SEARCHGW</td> <td style="text-align: left">L|关</td></tr> <tr> <td>0x02</td> <td style="text-align: left">GWINFO</td> <td style="text-align: left">|关信息</td></tr> <tr> <td>0x03</td> <td style="text-align: left">reserved</td> <td style="text-align: left">没有使用?/td></tr> <tr> <td>0x04</td> <td style="text-align: left">CONNECT</td> <td style="text-align: left">发vq接</td></tr> <tr> <td>0x05</td> <td style="text-align: left">CONNACK</td> <td style="text-align: left">q接认</td></tr> <tr> <td>0x06</td> <td style="text-align: left">WILLTOPICREQ</td> <td style="text-align: left">遗嘱主题h</td></tr> <tr> <td>0x07</td> <td style="text-align: left">WILLTOPIC</td> <td style="text-align: left">遗嘱主题认</td></tr> <tr> <td>0x08</td> <td style="text-align: left">WILLMSGREQ</td> <td style="text-align: left">遗嘱消息h</td></tr> <tr> <td>0x09</td> <td style="text-align: left">WILLMSG</td> <td style="text-align: left">遗嘱消息认</td></tr> <tr> <td>0x0A</td> <td style="text-align: left">REGISTER</td> <td style="text-align: left">注册主题</td></tr> <tr> <td>0x0B</td> <td style="text-align: left">REGACK</td> <td style="text-align: left">注册认</td></tr> <tr> <td>0x0C</td> <td style="text-align: left">PUBLISH</td> <td style="text-align: left">发布消息</td></tr> <tr> <td>0x0D</td> <td style="text-align: left">PUBACK</td> <td style="text-align: left">发布认</td></tr> <tr> <td>0x0E</td> <td style="text-align: left">PUBCOMP</td> <td style="text-align: left">发布环节消息</td></tr> <tr> <td>0x0F</td> <td style="text-align: left">PUBREC</td> <td style="text-align: left">发布环节消息</td></tr> <tr> <td>0x10</td> <td style="text-align: left">PUBREL</td> <td style="text-align: left">发布环节消息</td></tr> <tr> <td>0x11</td> <td style="text-align: left">reserved</td> <td style="text-align: left">保留字段</td></tr> <tr> <td>0x12</td> <td style="text-align: left">SUBSCRIBE</td> <td style="text-align: left">订阅主题</td></tr> <tr> <td>0x13</td> <td style="text-align: left">SUBACK</td> <td style="text-align: left">订阅认</td></tr> <tr> <td>0x14</td> <td style="text-align: left">UNSUBSCRIBE</td> <td style="text-align: left">退?/td></tr> <tr> <td>0x15</td> <td style="text-align: left">UNSUBACK</td> <td style="text-align: left">退订确?/td></tr> <tr> <td>0x16</td> <td style="text-align: left">PINGREQ</td> <td style="text-align: left">Pingh</td></tr> <tr> <td>0x17</td> <td style="text-align: left">PINGRESP</td> <td style="text-align: left">Ping响应</td></tr> <tr> <td>0x18</td> <td style="text-align: left">DISCONNECT</td> <td style="text-align: left">断开</td></tr> <tr> <td>0x19</td> <td style="text-align: left">reserved</td> <td style="text-align: left">保留字段</td></tr> <tr> <td>0x1A</td> <td style="text-align: left">WILLTOPICUPD</td> <td style="text-align: left">遗嘱主题更新</td></tr> <tr> <td>0x1B</td> <td style="text-align: left">WILLTOPICRESP</td> <td style="text-align: left">遗嘱主题更新认</td></tr> <tr> <td>0x1C</td> <td style="text-align: left">WILLMSGUPD</td> <td style="text-align: left">遗嘱消息更新</td></tr> <tr> <td>0x1D</td> <td style="text-align: left">WILLMSGRESP</td> <td style="text-align: left">遗嘱消息更新认</td></tr> <tr> <td>0x1E-0xFD</td> <td style="text-align: left">reserved</td> <td style="text-align: left">保留字段</td></tr> <tr> <td>0xFE</td> <td style="text-align: left">转发装标志</td> <td style="text-align: left">用于转发</td></tr></tbody></table> <h3 id="-">消息可变部分</h3> <p>可变字段很多Q与MQTT相比Q多了:</p> <ol> <li>持箋旉字段QDurationQ? </li><li>标识WFlags有所不同Q下面表D行说? </li><li>|关地址QGwAddQ,可变长度Q但依赖于底层网l,在ZigBee|络?个字节长? </li><li>一个字节网关IdQGwIdQ? </li><li>协议IdQProtocolIdQ,一个字节,唯一?<strong>0x01</strong>Q统一表示协议名称和协议名U? </li><li>q播路径x(q播路径深度/q播辐射范围)QRadiusQ一个字节表C,0x00表示q播l当前网l中所有节? </li><li>CONNECT/REGISTER/SUBSCRIBE/PUBLISH{消息对应回执中都会包含q回码Recode CodeQ见下表?</li></ol> <table> <thead> <tr> <th>q回?/th> <th style="text-align: left">q回值含?/th></tr></thead> <tbody> <tr> <td>0x00</td> <td style="text-align: left">接受h(Accepted)</td></tr> <tr> <td>0x01</td> <td style="text-align: left">因拥塞拒l?Rejected: congestion)Q一般需要接收方{待T_WAIT旉?/td></tr> <tr> <td>0x02</td> <td style="text-align: left">因非法主题标识符拒绝(Rejected: invalid topic ID)</td></tr> <tr> <td>0x03</td> <td style="text-align: left">因不支持拒绝(Rejected: not supported)</td></tr> <tr> <td>0x04 - 0xFF</td> <td style="text-align: left">保留Q没有用到</td></tr></tbody></table> <h3 id="-">具体消息格式说明</h3> <h4 id="advertise">ADVERTISE</h4> <p>|关周期性会对当前网l下所有客L、节点进行广播,用于客户端发现可用网兟?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x05</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x00</td></tr> <tr> <td>2</td> <td>GwId</td> <td style="text-align: left">|关需要吧自n标识W包含其?/td></tr> <tr> <td>3-4</td> <td>Duration</td> <td style="text-align: left">|关的下ơ广播间隔时长,单位U?/td></tr></tbody></table> <h4 id="searchgw">SEARCHGW</h4> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x03</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x01</td></tr> <tr> <td>2</td> <td>Radius</td> <td style="text-align: left">q播半径深度Q同时也是只是给当前|络传输?/td></tr></tbody></table> <p>客户端主动寻扄兌行广播的消息Q广播\径范围受限于当前|络环境下的客户端部|密度,比如只有1跛_播在非常密集的网l环境下客户端都可以彼此互相讉K?/p> <h4 id="gwinfo">GWINFO</h4> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态确?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x02</td></tr> <tr> <td>2</td> <td>GwId</td> <td style="text-align: left">|关Id</td></tr> <tr> <td>3-n</td> <td>GwAdd*</td> <td style="text-align: left">一个网兛_址Q仅仅由客户端发出消息时Q此字段才存?/td></tr></tbody></table> <p>GWINFO作ؓ对SEARCHGW消息的响应:</p> <ul> <li>若由|关发出Q则无GwAdd字段 </li><li>若来自于客户端,需要包含网兛_址 </li></ul> <h4 id="connect">CONNECT</h4> <p>客户端向|关发出建立q接的消息?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x04</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3</td> <td>ProtocolId</td> <td style="text-align: left">0x01Q表C协议版本和协议名称</td></tr> <tr> <td>4-5</td> <td>Duration</td> <td style="text-align: left">存活持箋旉</td></tr> <tr> <td>6-n</td> <td>ClientId</td> <td style="text-align: left">客户端标识符Q?-23个字节表C的字符?/td></tr></tbody></table> <p>在CONNECT消息标志位具体表C如下:</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">0/1</td> <td style="text-align: center">0/1</td> <td style="text-align: center">X</td></tr></tbody></table> <ul> <li>0/1 表示具体值待? </li><li>X 表示没有使用?</li></ul> <p>在Flags中用到的标志位Q?/p> <ol> <li>WillQ若?Q客L会在E后h遗嘱主题和遗嘱消? </li><li>CleanSessionQ不但表C阅持久化Q同时也被可扩展到遗׃题和遗嘱消息?</li></ol> <h4 id="connack">CONNACK</h4> <p>|关对客L发出CONNECT消息的响应?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x03</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x05</td></tr> <tr> <td>2</td> <td>ReturnCode</td> <td style="text-align: left">接受?x00Q拒lؓ0x01-0x03Q具体见上文RecodeCode定义</td></tr></tbody></table> <h4 id="willtopicreq">WILLTOPICREQ</h4> <p>Ҏ客户端CONNECT标志位中WILL字段为true情况下,|关向客L发出遗嘱主题hQ格式如下:</p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th>说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td>0x02</td></tr> <tr> <td>1</td> <td>MsgType</td> <td>0x06</td></tr></tbody></table> <p>只有头部部分Q很单?/p> <h4 id="willtopic">WILLTOPIC</h4> <p>客户端作为网关WILLTOPICREQh响应消息。下面是一个正常版本的WILLTOPIC消息Q?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x07</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3-n</td> <td>WillTopic</td> <td style="text-align: left">遗嘱主题</td></tr></tbody></table> <p>此时的标志位如下</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">X</td> <td style="text-align: center">0x00-0x02</td> <td style="text-align: center">0/1</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td></tr></tbody></table> <p>而空的WILLTOPIC也是允许存在的,׃个字节表C,用于客户端请求删除已存在于服务器端的对应遗嘱主题和消息?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th>说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td>0x02</td></tr> <tr> <td>1</td> <td>MsgType</td> <td>0x07</td></tr></tbody></table> <h4 id="willmsgreq">WILLMSGREQ</h4> <p>Ҏ客户端CONNECT标志位中WILL字段为真情况下,|关向客L发出遗嘱消息hQ格式如下:</p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th>说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td>0x02</td></tr> <tr> <td>1</td> <td>MsgType</td> <td>0x08</td></tr></tbody></table> <p>只有头部部分Q没有别的?/p> <h4 id="willmsg">WILLMSG</h4> <p>客户端对|关WILLMSGREQh的响应,从而把遗嘱消息传递给|关q行保存?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x09</td></tr> <tr> <td>2-n</td> <td>WillMsg</td> <td style="text-align: left">客户端遗?/td></tr></tbody></table> <h4 id="register">REGISTER</h4> <ul> <li>客户?->|关Q请求主题(topic nameQ对应的主题标识W(topic idQ? </li><li>|关-->客户端,通知主题Qtopic nameQ已l被指派到某个主题标识符Qtopic idQ?</li></ul> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x0A</td></tr> <tr> <td>2-3</td> <td>TopicId</td> <td style="text-align: left">客户端发出,此gؓ0x0000Q服务器发出Q需要包含对应于Topic Name的主题标识符</td></tr> <tr> <td>4-5</td> <td>MsgId</td> <td style="text-align: left">自然敎ͼ用以标识对应的REGACK认</td></tr> <tr> <td>6-n</td> <td>TopicName</td> <td style="text-align: left">主题名称Q不能太长,量不要使用通配W?/td></tr></tbody></table> <h4 id="regack">REGACK</h4> <p>客户端或|关针对REGISTER消息的响应?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x07</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x0B</td></tr> <tr> <td>2-3</td> <td>TopicId</td> <td style="text-align: left">对应于Topic Name的主题标识符Q被用于PUBLISH消息发布</td></tr> <tr> <td>4-5</td> <td>MsgId</td> <td style="text-align: left">自然敎ͼ用以标识对应的REGISTER消息</td></tr> <tr> <td>6</td> <td>ReturnCode</td> <td style="text-align: left">0x00被接受,其它D拒绝</td></tr></tbody></table> <h4 id="publish">PUBLISH</h4> <p>PUBLISH消息用于客户端或|关发布消息用:</p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x0C</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3-4</td> <td>TopicId</td> <td style="text-align: left">主题标识W?/td></tr> <tr> <td>5-6</td> <td>MsgId</td> <td style="text-align: left">QoS 1-2旉要填充自然|QoS 0Ӟgؓ0x0000</td></tr> <tr> <td>7-n</td> <td>Data</td> <td style="text-align: left">用于发布的具体消息内?/td></tr></tbody></table> <p>标识位具体如下:</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">0/1</td> <td style="text-align: center">0x00-0x02</td> <td style="text-align: center">0/1</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">0b00/0b01/0b10</td></tr></tbody></table> <p>标识位里面各个字D和MQTT协议一_无须多解释?/p> <h4 id="puback">PUBACK</h4> <p>客户?|关仅仅对QoS 1/2的PUBLISH消息做出响应?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x07</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x0D</td></tr> <tr> <td>2-3</td> <td>TopicId</td> <td style="text-align: left">对应PUBLISH消息中TopicId</td></tr> <tr> <td>4-5</td> <td>MsgId</td> <td style="text-align: left">自然敎ͼ用以标识对应的REGISTER消息</td></tr> <tr> <td>6</td> <td>ReturnCode</td> <td style="text-align: left">0x00被接受,其它D拒绝Q不同DCZ同拒l理?/td></tr></tbody></table> <p>处理PUBLISH消息异常Q在PUBACK消息中的ReturnCode字段中以相应g现出来,q就要求接收者处理拒l理由?/p> <h4 id="pubrec-pubrel-pubcomp">PUBREC, PUBREL, PUBCOMP</h4> <p>只有在PUBLISH消息中QoS 2ӞPUBREC, PUBREL, PUBCOMP才会一L场,否则是没有出场机会的。消息格式嘛Q都很统一Q?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x04</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x0F/0x10/0x0E</td></tr> <tr> <td>2-3</td> <td>MsgId</td> <td style="text-align: left">对应PUBLISH消息中的MsgId</td></tr></tbody></table> <h4 id="subscribe">SUBSCRIBE</h4> <p>SUBSCRIBE用于客户端订阅某个主题的消息?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x12</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3-4</td> <td>MsgId</td> <td style="text-align: left">用于定对应的订阅确认SUBACK消息</td></tr> <tr> <td>5-N</td> <td>TopicId/TopicName</td> <td style="text-align: left">具体需要根据Flags标志位中TopicIdTypeq行填充</td></tr></tbody></table> <p>标识位具体如下:</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">0/1</td> <td style="text-align: center">0x00-0x02</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">0b00/0b01/0b10</td></tr></tbody></table> <p>此处Q标志位中TopicIdType军_了SUBSCRIBE消息中TopicId/TopicName字段具体填充|预定义topic idQ或短小两个字符表示主题Qtopic nameQ,或直接填写主题?/p> <h4 id="suback">SUBACK</h4> <p>|关->客户端,订阅处理情况的确认回执,接受订阅或出于其它原因拒l之?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x08</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x13</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3-4</td> <td>TopicId</td> <td style="text-align: left">|关接受其注册,此处对应具体指派的TopicId</td></tr> <tr> <td>5-6</td> <td>MsgId</td> <td style="text-align: left">SUBSCRIBE消息中对应MsgId?/td></tr> <tr> <td>7</td> <td>ReturnCode</td> <td style="text-align: left">0x00被接受,其它D拒绝</td></tr></tbody></table> <p>标识位具体如下:</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">X</td> <td style="text-align: center">0x00-0x02</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td></tr></tbody></table> <p>SUBACK消息标志位中QoS为网x据实际情冉|权后的QoS具体|q也应该是客L需要知道ƈ处理的?/p> <h4 id="unsubscribe">UNSUBSCRIBE</h4> <p>UNSUBSCRIBE用于客户端取消订阅某个主题的消息?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x14</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3-4</td> <td>MsgId</td> <td style="text-align: left">用于定对应的退订确认UNSUBACK消息</td></tr> <tr> <td>5-N</td> <td>TopicId/TopicName</td> <td style="text-align: left">具体需要根据Flags标志位中TopicIdTypeq行填充</td></tr></tbody></table> <p>标识位具体如下:</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">0b00/0b01/0b10</td></tr></tbody></table> <p>UNSUBSCRIBE消息标志位中唯一可用属性TopicIdType军_了UNSUBSCRIBE消息中TopicId/TopicName字段具体填充倹{?/p> <h4 id="unsuback">UNSUBACK</h4> <p>|关->客户端,取消订阅处理情况的确认回执,很简单,4个字节表C?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x04</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x15</td></tr> <tr> <td>2-3</td> <td>MsgId</td> <td style="text-align: left">UNSUBSCRIBE消息中对应MsgId?/td></tr></tbody></table> <h4 id="pingreq">PINGREQ</h4> <p>和MQTT协议中的PINGREQ一_存活?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x16</td></tr> <tr> <td>2-N</td> <td>ClientId</td> <td style="text-align: left">可选项Q表C客L休眠状态{换ؓ唤醒状态用于检查网x否ؓ其缓存消?/td></tr></tbody></table> <h4 id="pingresp">PINGRESP</h4> <p>接受PINGREQ消息的一方,如网兛_应PINGRESP消息表示自己现在q行OK?/p> <p>另外一个意图,若唤醒状态客L发送PINGREQ消息之后Q直接收到PINGRESP消息Q表C网兛_前暂时没有ؓ其缓存的消息可供发送?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th>说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td>0x02</td></tr> <tr> <td>1</td> <td>MsgType</td> <td>0x17</td></tr></tbody></table> <p>很简单,两个字节表示矣?/p> <h4 id="disconnect">DISCONNECT</h4> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x18</td></tr> <tr> <td>2-3</td> <td>Duration</td> <td style="text-align: left">可选项Q表C客L卛_q入睡眠状态的持箋旉?/td></tr></tbody></table> <ul> <li>客户?>|关Q客Ld关闭当前q接Q网兛_应确认消息。只有表Cp入睡眠状态的客户端,才会在DISCONNECT消息中附加Duration持箋字段? </li><li>|关->客户端,|关׃异常d通知客户端关闭两者之间连接,客户端接收到DISCONNECT旉要发送CONNECT消息到网养I重试重新建立q接。没有Duration字段填充?</li></ul> <p>|关接收到要q入休眠状态的客户端发送的包含有Duration字段DISCONNECT消息Ӟ可以直接q回2个字节的Q不能包含有Duration字段QDISCONNECT消息以示认?/p> <h4 id="willtopicupd">WILLTOPICUPD</h4> <p>客户端发送请求网x新其遗嘱主题?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x1A</td></tr> <tr> <td>2</td> <td>Flags</td> <td style="text-align: left">标志?/td></tr> <tr> <td>3-N</td> <td>WillTopic</td> <td style="text-align: left">用于更新的遗׃?/td></tr></tbody></table> <p>标识位具体如下:</p> <table> <thead> <tr> <th style="text-align: center">DUP</th> <th style="text-align: center">QoS</th> <th style="text-align: center">Retain</th> <th style="text-align: center">Will</th> <th style="text-align: center">CleanSession</th> <th style="text-align: center">TopicIdType</th></tr></thead> <tbody> <tr> <td style="text-align: center">bit 7</td> <td style="text-align: center">6,5</td> <td style="text-align: center">4</td> <td style="text-align: center">3</td> <td style="text-align: center">2</td> <td style="text-align: center">1,0</td></tr> <tr> <td style="text-align: center">X</td> <td style="text-align: center">0x00-0x02</td> <td style="text-align: center">0/1</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td> <td style="text-align: center">X</td></tr></tbody></table> <p>协议规定只有两个字节IWILLTOPICUPD也是允许存在的,存在意义用于客户端请求网兛_除已保存的遗׃题和遗嘱消息{?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x02</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x1A</td></tr></tbody></table> <h4 id="willtopicresp">WILLTOPICRESP</h4> <p>WILLTOPICRESP为网x到WILLTOPICUPD后作出的应答消息?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x03</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x1B</td></tr> <tr> <td>2</td> <td>ReturnCode</td> <td style="text-align: left">0x00被接受,其它D拒绝</td></tr></tbody></table> <h4 id="willmsgupd">WILLMSGUPD</h4> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">动态计?/td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x1C</td></tr> <tr> <td>2-N</td> <td>WillMsg</td> <td style="text-align: left">用于更新的遗嘱消?/td></tr></tbody></table> <p>客户?>|关Q确认更新的遗嘱消息?/p> <h4 id="willmsgresp">WILLMSGRESP</h4> <p>WILLMSGRESP为网x到WILLMSGUPD后作出的应答消息?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">0x03</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0x1D</td></tr> <tr> <td>2</td> <td>ReturnCode</td> <td style="text-align: left">0x00被接受,其它D拒绝</td></tr></tbody></table> <h3 id="-">转发装</h3> <p>在MQTT-SN架构图中QMQTT-SN Forwarder转发器适用于客L无法直接讉K|关或当前传感器|络区域中不存在|关Ӟ转发器作用就体现出来了:</p> <ol> <li>接收MQTT-SN客户端消息封装后转发l上游网? </li><li>解封上游|关所发送消息,直接发送给对应客户?</li></ol> <p>转发器作用于消息的封装{发,解封发送,针对消息不做修改?/p> <p>转发器对MQTT-SN消息装格式Q?/p> <table> <thead> <tr> <th>字节索引</th> <th>表示内容</th> <th style="text-align: left">说明</th></tr></thead> <tbody> <tr> <td>0</td> <td>Length</td> <td style="text-align: left">十进制表C长度就是N</td></tr> <tr> <td>1</td> <td>MsgType</td> <td style="text-align: left">0xFE</td></tr> <tr> <td>2</td> <td>Ctrl</td> <td style="text-align: left">包含|关和{发器之间的控制交换信息,主要是前两位包含了半径范?/td></tr> <tr> <td>3-N</td> <td>Wireless Node Id</td> <td style="text-align: left">标识所发目的或需要接收封装消息的无线节点</td></tr> <tr> <td>N+1-M</td> <td>MQTT-SN message</td> <td style="text-align: left">一个MQTT-SN消息消息</td></tr></tbody></table> <p>无线节点IdQWireless Node IdQ:</p> <ul> <li>转发?>|关Q无U节点Id{发器所在的无线节点IdQ便于告知网兌{发器位置 </li><li>|关->转发器,无线节点Id为网关的无线节点Id </li></ul> <p>控制交换字段CtrlQ单个字节,位表C含义:</p> <table> <thead> <tr> <th style="text-align: center">bit 7,2</th> <th style="text-align: center">1,0</th></tr></thead> <tbody> <tr> <td style="text-align: center">X</td> <td style="text-align: center">0x00-0x03</td></tr></tbody></table> <h3 id="-">结</h3> <p>MQTT-SN 1.2规范中所定义消息格式介绍完毕Q下一将对MQTT-SN主要程功、能q行阐述?/p></div><img src ="http://www.aygfsteel.com/yongboy/aggbug/422142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-01-08 21:52 <a href="http://www.aygfsteel.com/yongboy/archive/2015/01/08/422142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT-SN协议q之简要介l?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/01/07/422119.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 07 Jan 2015 14:41:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/01/07/422119.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/422119.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/01/07/422119.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/422119.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/422119.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"> <h3 id="-">前言</h3> <p>q一D|间在ȝMQTT-SN的协议,寚w对不依赖于TCP传输的MQTT协议十分感兴,L再想着q货到底是怎么定义的。一pd文章皆有MQTT-SN 1.2协议所Dl成Q原文档地址Q?<a >MQTT-SN_spec_v1.2.pdf</a></p> <p>MQTT-SN文档分ؓ7个部分,我直接按照从前到后的序Q直接组装成四个篇。嗯Q若攑֜一文章中Q文字太长,造成排版隑ֺ?/p> <p>非直译,完全按照自己理解整理而成Q请知晓?/p> <h3 id="-">版本变迁历史</h3> <ol> <li>2007-11-29 1.0版本 </li><li>2008-6-5 1.1版本Q增加休眠设备支? </li><li>2011-5-20 1.2版本 </li></ol> <ul> <li>增加消息长度255字节支持 </li><li>增加转发装支持 </li><li>增加q回代码"0x03 Rejected, not supported" </li><li>ReturnCode 增加到WILLTOPICRESP和WILLMSGRESP消息?</li></ul> <h3 id="mqtt-sn-">MQTT-SN名称由来</h3> <p>原名是MQTT-SQ但会引起h们的误解Q因此更名成MQTT-SNQ?/p> <blockquote> <p>As part of the job of applying the same or similar license terms to the MQTT-S specification as those on the MQTT specification, we are proposing a small name change. The new name would be MQTT-SN, standing for exactly the same long name, MQTT for Sensor Networks. Some people had assumed that the S in MQTT-S stood for secure, so we hope this change will avoid that confusion. -- Ian Craggs</p></blockquote> <h3 id="mqtt-sn-">MQTT-SN存在目的</h3> <blockquote> <p>MQTT for Sensor Networks is aimed at embedded devices on non-TCP/IP networks, such as Zigbee. MQTT-SN is a publish/subscribe messaging protocol for wireless sensor networks (WSN), with the aim of extending the MQTT protocol beyond the reach of TCP/IP infrastructure for Sensor and Actuator solutions.</p></blockquote> <p>针对适配传感装置Q羃写ؓSAQ的特定版MQTT协议Q一般运行在嵌入式电池驱动的电子元g中,传输通过ZIEEE 802.15.4规范无线低速网l构成的无线传感|络QWSNQ,同样h企业U别Ҏ具有以数据为核心的Qdata-centricQ订?发布Ҏ?/p> <p>MQ针对低功耗、电池驱动、处理存储受限的讑֤、不支持TCP/IP协议栈网l的电子器g而定Ӟ比如常见的ZigBeeQ或XBeeQ,Ҏ依赖的底层传输网l不可知Q但只要|络支持双向数据传输和网养I都是可以支持较ؓ上层的MQTT-SN协议传输。比如简单数据报服务Q只要支持一个源端点发送数据到一个特定目的地端点Q这Ҏ持MQTT-SN协议Q就_了。广播数据报传输服务也是必须的用于网兛_l端的自动发现流E。ؓ了降低广播风_MQTT-SN定义了广播\径深度(q播范围或广播半径)?/p> <h3 id="-">一些名词和术语</h3> <ul> <li>topic idQ主题标识符Q两个字?6位表C的自然敎ͼjava语言shortcdQ?-65535范围Q,对应于主题topic name </li><li>|关/服务器(gateway/serverQ,在MQTT-SN中统一UC为网养I主要处理和MQTT-SN客户端的交互Q羃写ؓ|关 </li><li>MQTT-SNl端和客LQclientQ,l一UC为客LQ其实也是嵌入式传感讑֤Q或电子元gQ资源受限,在无U区域个人网中运? </li><li>IEEE 802.15.4Q完整栈的整个数据上限ؓ128个字节,一般选择UDPQ相?0个字节的TCP协议QUDP报文头部仅仅需?个字节)协议传输数据 </li><li>低速网l?当前|络Q指的是LR-WPANQlow-rate wireless personal area network,Q,低速无U个人区域网l?</li></ul> <h3 id="mqtt-sn-vs-mqtt">MQTT-SN VS MQTT</h3> <p>管MQTT-SN被设计成可能接q于MQTTQ但那些低功耗、电池驱动、资源受限的讑֤所在网l场景ؓ低速带宽、高q接p|、物理层数据包上Uؓ128字节。文档提Z以下不同点:</p> <ol> <li>CONNECT消息被拆分成三个消息QCONNECTQWILLTIPIC<em>QWILLMSG</em>Q,后两者用于客L传递遗׃题和遗嘱消息{? </li><li>在PUBLISH消息中主题(topic nameQ被替换成两个字节长度自然数Qtopic idQ,q个需要客L通过注册程q行获取对应的topic id </li><li>预定义(提前定义Qtopic id和topic nameQ省M间注册流E,客户端和|关要求提前在其Zg中指? </li><li>协议引入的自动发现机制可帮助客户端发现潜在的|关。若存在多个|关Q彼此可协调是ؓM互备或者负载均? </li><li>"clean session"卛_作用于订阅持久化Q也被扩展作用于遗嘱Ҏ(遗嘱主题和遗嘱消息) </li><li>针对休眠讑֤增加ȝ保活机制支持Q当有消息时代理需要缓存,客户端被唤醒时再发?</li></ol> <h3 id="mqtt-sn-">MQTT-SN架构C意</h3> <p><img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/mqtt-sn-01.jpg" /></p> <p>在MQTT-SN架构图中Q存在三U组Ӟ</p> <ol> <li>MQTT-SN 客户? </li><li>MQTT-SN |关Q可单独存在Q也可以被集成到MQTT服务器中。需要承担MQTT-SN和MQTT协议之间的{换工? </li><li>MQTT-SN 转发器,负责转发当前客户端数据到不可直接讉K的网关上去,针对客户端而言|关不可直接讉KӞ转发器作用就凸显。{发器装MQTT-SN消息转发l网养I解封来自|关的消息发送给客户端。网关不能够改原始数据?</li></ol> <h4 id="mqtt-sn-">MQTT-SN传输|关</h4> <p>MQTT-SN|关传输方式Q下面的囄一目了然?<img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/mqtt-sn-02.jpg" /></p> <ol> <li>透明|关Q会为每一个客L都徏立一个TCPq接到MQTT服务器的通道Q这样会较ؓ耗费|关|络资源Q但模型? </li><li>聚合|关Q只建立一条TCPq接通道到MQTT服务器上Q所有的客户端共享一个通道Q很l济的说?</li></ol> <p>|关需要抉择哪些消息需要和q程的MQTT Serverq行交互Q比如只选择客户端发送的PUBLISH、SUBSCRIBLE消息{?/p> <h3 id="-">结</h3> <p>上面单介l了MQTT-SNQ下面将会介lMQTT-SN消息头部和格式?/p></div><img src ="http://www.aygfsteel.com/yongboy/aggbug/422119.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-01-07 22:41 <a href="http://www.aygfsteel.com/yongboy/archive/2015/01/07/422119.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT 3.1.1Q值得升?个新Ҏ?/title><link>http://www.aygfsteel.com/yongboy/archive/2014/12/16/421460.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 16 Dec 2014 05:59:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2014/12/16/421460.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/421460.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2014/12/16/421460.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/421460.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/421460.html</trackback:ping><description><![CDATA[<h3>前言</h3> <p>以前看英文文章或资料Q看完之后,摘要或者忘记。这一ơ选择感兴的MQTT 3.1.1介绍文章资料Q引文见文末Q作为练手;非完全翻译,去除掉一些广告性描qͼ若R权,请告知?/p> <p>在沉寂了四年之后Q?a >QTT 3.1.1规范</a>?014q?0?0h式发布,与此同时MQTT 3.1.1已成为OASISQ结构化信息标准促进l织Q开攄联网消息传递协议标准(<a >q接1</a> <a >q接2</a>Q,换种说法是MQTT 3.1.1已升Uؓ国际物联|标准?/p> <blockquote> <p>正如HTTPZh们通过万维|分享信息铺q了道\一PMQTT能将几十亿低成本、嵌入式数据采集遥测讑֤q接到网l?/p></blockquote> <p>与MQTT 3.1Q还不是国际物联|标准呢Q规范相比,MQTT 3.1.1目标在于消除歧义Q尽可能的向后兼容,事实上一些大众所需的新Ҏ被包含在这个版本(更多的是物联|标准推动)Q因此不仅是一个维护版本,也是一U巨大的q步呢。除了概늚澄清和陈旧规范重写外Q有一些很有趣的变化是值得注意的?/p> <h3>会话表示标志QSession Present FlagQ?/h3> <p>如果一个终端与服务器之间徏立一个持久会话连?假设q个l端没有使用C?#8220;clean session”标记清除已有回话标志), 一个新增的“Session Present”标志Q会话表C标志,逻辑gؓtrue或falseQ会在CONNACK中出玎ͼ表明MQTT服务器已l拥有当前客L上次q接会话信息Q比如订阅的主题Q排队信息和其它信息{?/p> <p>会话表示标志若ؓtrueQ客L可减了一ơ发送订阅SUBSCRIBLE交互步骤Q有助于更有效的数据通信QؓfalseQ客L需要再ơ发送订阅SUBSCRIBLE消息Q不可略q?/p> <h3>新增订阅p|代码反馈</h3> <p>MQTT 3.1.1之前Q终端连接之后无法知道其发送的订阅主题是否被MQTT服务器接受与否。此新特性较适用于细_度权限MQTT主题理Q若无授权,服务器会把错误代?0x80)附加在SUBACK中,客户端就可以知道订阅p|?/p> <h3>MQTT匿名客户?/h3> <p>需要支持时或匿名Q客L仅仅需要在发送CONNECT时把客户端标识符Q?client identifier Q置I(雉度)卛_QMQTT服务器会为此c请求生成一个随机、唯一客户端标记符。但q要求客L必须讄Clean Session标记?Q否则服务器端会直接q回包含0x02 (Identifier rejected)代码的CONNACKQ同时关闭连接?/p> <p>可用于后端程序(不需要维护回话状态)向终端发送消息的客户端,MQTT服务器程序可区别对待?/p> <h3>快速发布无{待</h3> <p>q是一个新增的特别有用的特性,客户端可以在发送CONNECT之后Q可无须{待MQTT服务器返回的CONNACKQ根据需要即d送PUBLISH、SUBSCRIBLE、DISCONNEECT{消息,可避免客L资源{待。此Ҏ也适用于突发模式(burst-modeQ客L需求,只关心数据要快的发送出去,而不是去担心是否需要维护一个长q接?/p> <p>q需要MQTT服务器实现在分发消息之前查客L是否有权限发布到q些主题上?/p> <h3>客户端标识符可以变长一?/h3> <p>MQTT 3.1针对客户端标识符Q?client identifierQ限制是23个字节,实际环境下会有所不便Q已有遗留系l可能用UUID作ؓ客户端的标识W,q样服务器端需要做一些彼此之间的MAP映射?MQTT 3.1.1中上限ؓ65535个字节,毕竟成ؓ业界标准Q需要兼容大量的遗留讑֤和基设施?/p> <h3>其它改?/h3> <ol> <li>CONNECT消息可变头部协议名称MQIsdp被改为MQTTQ语义更准确 </li><li>所有字W串明确规定使用UTF-8~码Q包括客L标识W?Client Identifier) </li><li>CONNECT消息可变头部协议版本P?x03变成?x04 QoS 0cdPUBLISH消息DUP标记必须被设|ؓ0 </li><li>MQTT Over WebSocket 被定义,互联|地址~码分配机构QInternet Assigned Numbers AuthorityQ分配标识符为mqtt。虽在MQTT 3.1规范通篇没有提到WebSocketQ但因其二进制属性可以很Ҏ的在WebSocket通道传输?</li></ol> <h3>术语变化</h3> <ul> <li>MQTT代理 -> MQTT服务器(MQTT Broker is now MQTT ServerQ? </li><li>消息ID -> 包IDQMessage ID is now Packet IDQ? </li><li>消息cd -> 包类型(Message Type is now Packet TypeQ? </li><li>主题路径 -> 主题名称QSubscribe and Unsubscribe take Topic Paths, rather than Topic namesQ? </li><li>以前在固定头部,现在在包cd? Flags in the fixed header are now specific to the packet type </li><li>0字节保留信息需要清?QA zero byte retained message MUST NOT be stored as a retained message on the Server Q?</li></ul> <h3>结</h3> <p>当前MQTT 3.1.1已经在很多活跃开源项?商业产品得到支持。比如Eclipse PahoQMosquittoQJBoss A-MQ 6.1, Apache ActiveMQ 5.10-SNAPSHOTQApache Camel 2.13.0QHiveMQ{?/p> <p>关于Eclipse Paho:</p> <ol> <li>Eclipse Paho 1.0支持MQTT 3.1.1和MQTT 3.1规范 </li><li>Eclipse Paho 0.9仅支?MQTT 3.1规范 </li></ol> <p>包含MQTT 3.1.1和MQTT 3.1的客L可以混合使用Q彼此可以共存于同一个MQTT服务器下Q在基本消息传输层面没有多大修改Q同LPUBLISH消息可以在MQTT客户端中自由{Q这个需要服务器端编码支持?/p> <p>已有的MQTT 3.1客户端可以用着急升U,但升U之后可以从新增Ҏ中收益良多?/p> <h3>引用</h3> <ol> <li><a >6 facts why it’s worth upgrading to the brand new MQTT 3.1.1 version</a> </li><li><a >Differences between 3.1.0 and 3.1.1</a> </li><li>other …… </li></ol><img src ="http://www.aygfsteel.com/yongboy/aggbug/421460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2014-12-16 13:59 <a href="http://www.aygfsteel.com/yongboy/archive/2014/12/16/421460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT 3.1协议非严肃反思录http://www.aygfsteel.com/yongboy/archive/2014/12/12/421331.htmlnieyongnieyongFri, 12 Dec 2014 02:19:00 GMThttp://www.aygfsteel.com/yongboy/archive/2014/12/12/421331.htmlhttp://www.aygfsteel.com/yongboy/comments/421331.htmlhttp://www.aygfsteel.com/yongboy/archive/2014/12/12/421331.html#Feedback14http://www.aygfsteel.com/yongboy/comments/commentRss/421331.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/421331.html前言

MQTT 3.1协议在弱|络环境下(比如2G/3G{)表现不够好,因此才有了反思?/p>

q环境下表?/h3>

手机{终端在ql环境下丢包情况会非常明显,q接MQTT Server成功率很低。相比单U的h-相应模型的HTTPQ其成功率会比MQTT订阅成功高很多?/p>

手机l端在每ơTCP断开或断|后Q会卛_发vTCP重连Q连接成功,会重复以前步骤依ơ发送连接命令(CONNECTQ,订阅命oQSUBSCRIBLEQ,表明上看Q这些过E没有Q何问题,但问题就在于从终端成功徏立到服务器的q接Q到发送订阅命令,在弱|情况下Q这个过E将会变得很昂贵Q?/p>

从TCP建立开始的三次握手到完整的订阅命o发送完毕,考虑到TCP堆栈的每ơ接收数据方响应ACKQ这中间l端和服务器端至生了10ơ数据交互?

在网l变化频J或者不太稳定的2G/3G|络环境下,q种q程昑־有些冗长和不适应Q同时会加重已经不堪的弱|络负蝲的负担?/p>

q下,在Q何一个阶D늚执行q程中,都有可能产生H发性的|络中断的问题:

  1. 无法成功建立TCP链接Q或d三次握手期间Q或数据包丢失在握手之后Q或客户端连接超时过?/p>

  2. 建立q接后,发送CONNECT命o后,或没接收到TCP ACK认包,或客L{待延时太小Q导致订阅命令交互失?/p>

  3. 发送SUBSCRIBLE命o后,但服务器端没收到Q或因ؓ丢包Q或|络已断开Q导致发送SUBSCRIBLE命op|

  4. 成功发送SUBSCRIBLE命o后,或移动网l断开了(有些q营商针对认为HTTP的请求有时判断Q,或等待超ӞD订阅p|

TCP是无感知的虚拟连接,中间断开两端不会立刻得到通知Q否则就用不着心蟩保活机制了?/p>

举一个例子,U上的服务器Ҏ日志分析Q只接收到连接命令(CONNECTQ但没有后箋的订阅命令(SUBSCRIBLEQ的情况Q每天有上百万别的数量?/p>

MQ针对低速率ql环境,MQTT表现不怎么好?/p>

改进?/h4>

业务改进点:

  1. 客户端的q接时、等待超时设大一点,两秒太短Q可讄长一些,比如10U?
  2. 服务器端支持在接收到用户发送CONNECT命o后,瞬间发送一些live data/hot dataQ早已缓存的数据Q,cM于HTTPh-相应模型Q目的嘛Q一些热数据发送给l端要趁早,快好Q所谓出名要早嘛)Q这个需要客L、服务器端同时支?

协议改进点:

  1. CONNECT命o可变头部包含"MQisdp"太多余了Q学院派风格?
  2. 允许在连接命令中负蝲QpayloadQ中携带订阅Topic字符?
  3. 允许在连接命令中表示上次q接订阅的Topic发生变化否,携带订阅业务Q虽冗余Q但实用?egQ订阅的Topic没有发生变化QTOPICCHANGE:0Q退订,UNSUBSCRIBE:TOPICONEQSUBSCRIBEQTOPIC_TWO
  4. PUBLISH、PUBACK{支持的 Message Identifier ?6位,太短Q实际业务无法做到全局唯一。引入mid和业务id的映对应关p?那是状态,需要维护,代hq是蛮高的。业界流行看法,无状态化的架构才是便于横向、竖向、纵向、四方向的扩展,呵呵。最好方式就是修改之支持字W串形式Q否则维护代价高Q?
  5. 心蟩命oPINGREQ/PINGREQ可以做到一个字节传输,节省一个字节,有些症的感觉?
  6. 低速率|络需要做一些兼容和调整

有些看似冗余Q批量或打包处理L单个处理更高效一些、更节省资源Q弱|络环境要求交互要尽可能的少Q数据嘛要的是瞬间抵达,快好?/p>

严格的分层和业务解耦,会导致性能问题。好比当前Linux内核的TCP/IP|络堆栈分层很清晎ͼ每一层都各司其职Q但和直接略q内核态直接运行在用户?User Space)的Packet I/O相比Q处理性能不是在一个档ơ上Q比如Netmap 、DPDK{?/p>

MQTT-SN

针对没有TCP/IP{网l堆栈支持的l端环境QMQTTp能助了?/p>

在一些类g传感器电子元件中Q资源十分受限,计算能力不Q嵌入TCP/IP|络堆栈不现实,比较好的方式ZIEEE 802.15.4用于低速无U个人域|?LR-WPAN)的物理层和媒体接入控制层规范之上发送UDP数据包,每一个数据包最?28个字节?/p>

MQTT-SNQMQTT For Sensor NetworksQ协议就是ؓ了非常受限类g感器而设的,协议程架构比较有趣Q?/p>

Image

更多协议l节Q有待进一步阅诅R?/p>

TCP不是最适合的移动网l传输协?/h3>

先来一下网l传输的字节数?/p>

以太|头至?8个字节,IP头固?0个字节,TCP?0个字节(UDP头部8个字节)Q再加上电信宽带计费的PPPoE?个字节:

  • TCP数据包头部信息至占?6个字?
  • UDP数据报头部信息至占?4个字?

UDP可以比TCP节省12个字节?/p>

MQTT-SN协议选择使用UDPQ可以看出其在节省资源方面的努力?/p>

再看看弱|环境?/p>

  • 在网l可达情况下QUDP可以在TCP建立W一ơ握手期间就已经把数据送达目的?
  • 完成三次握手期间QUDP客户端和UDP服务器在数据层面可以完成一ơ完整的交互QPING-PONGQ?

在网l不好的情况下,UDP的时效性会好于TCPQTCP长连接中间交换过多、之徏立完整交互的q程成功率就很低。此U情况UDP的低延迟和实时性呈现的l果会表现的很突出?/p>

TCP或HTTP理论上是可靠q接Q但是在|络不好的时候,也不是那么可靠。客L一般提交HTTPh之后Q没有确认是否提交成功,在弱|环境下会生丢包,服务器端嘛收不到。另TCP|络堆栈会存在数据包重发机制 + 应用层重发请求,可能会导致内核处理多ơ数据包的重发(q有拥塞H口会收~,发包速度减慢Q,可能会加重弱|络的负载?/p>

和TCP相比QUDP的无q接Q代表了它快速,资源消耗小Q突现就是gq较。至于数据包丢失没有重传Q上层的业务层面应用协议/机制可以保丢失的数据包重发或补发等Qƈ且会更透明Q安全的控性权。而TCP的包重发Q上层应用没有控制权限?/p>

q接协议斚wQ?/p>

  • TCP面向q接会生状态管理和l护Q成本不,比如l常看到的客Lreset异常{。一ơ完整的h周期必须固定在一台服务器?
  • UDP无连接的Ҏ。每ơ请求的数据包可以随机分配到不同的机器上q行处理Q可以做到完全无状态化横向扩展

MQ要实时性特诊,或者快速抵辄端的Ҏ,不妨考虑一下UDP。不q呢Q很多时候UDP和TCP大家会؜合着使用Q会互相弥补其不?/p>

若MQTT协议不能够满业务需求,或许可考虑选择定制Q或化流E,或用UDP重新实现Q或者用TCPQHTTP作ؓ补充{,不一而?/p>

xQ还真有点小Ȁ动呢Q?------ 《万万没惛_》王大锤



nieyong 2014-12-12 10:19 发表评论
]]>
MQTT协议W记之mqtt.io目HTTP协议支持http://www.aygfsteel.com/yongboy/archive/2014/06/06/414474.htmlnieyongnieyongFri, 06 Jun 2014 08:42:00 GMThttp://www.aygfsteel.com/yongboy/archive/2014/06/06/414474.htmlhttp://www.aygfsteel.com/yongboy/comments/414474.htmlhttp://www.aygfsteel.com/yongboy/archive/2014/06/06/414474.html#Feedback1http://www.aygfsteel.com/yongboy/comments/commentRss/414474.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/414474.html前言

MQTT协议诞生之初Q就未曾考虑通过HTTP传输。这也正常,|络受限、不E_|络不太适合HTTPQ?G/3G|络大家使用WAP不也OK嘛)。在|络较ؓ充裕的桌面端而言Q虽U文本对比二q制而言没多大优势,受制于历史遗留和使用习惯Q以及一大票传统基础设施方便控制事宜Q传l互联网/企业型应用,HTTP协议都是默认最佳选择Q安全可控,人机友好。选择HTTP也在情理之中?/p>

虽桌面端日渐式微Q但做统一的全q_化消息系l?消息中间Ӟ也是势?/p>

MQTT OVER HTTPQؓWEB环境提供HTTP通道协议支持Q在l一q_化这L考量下,显得合情合理?MQTT相比其它ZHTTP的交换协议而言Q比如socket.ioQ,量节省Q消息质量可控?/p>

一句话Q比它强大的Q没有它轻量。比它还ȝQ没有它可控?/p>

MQ在资源受限环境下表现如此优异,那么桌面端会表现的更ZU?/p>

HTTP支持情况

二进制支持,针对览器端JavaScript而言Q处理v来,如同在石器时代要处理工业时代一些通讯方式Q非常吃力。支持Javascript二进制操作的览器现Ӟ

xhr2

来源于:http://caniuse.com/xhr2

q和支持Websocket的浏览器的基本重叠?/p>

要想让HTTP传输MQTT具体消息二进Ӟ然后由浏览器javascript脚本q行解析Q无法做到支持所有常见浏览器Q需要考虑U文本方式的传输?/p>

设计摘要

AJAX方式Q支持跨域,支持所有主^収ͼ桌面+Ud讑֤Q所有浏览器Q移动的Q桌面的Q包括IE6+。那么最理想方式是JSONPQ基于文本通信的Long-polling JSONP方式?/p>

MQTT 协议关键交互点: 1. q接获取授权 1. 订阅/退订主?1. 发布消息 1. {待订阅消息 1. 关闭q接

若支持HTTP方式完成以上功能/步骤Q服务器端需要支持接收HTTPU文本内容请求,D、{换成Java对象Q业务层面实现数据流转、交换,直接插入到更具体业务中,q样很Ҏ。虽cM于桥接,但减了桥接的\径(HTTP —》MQTTQ,减少资源占用Q性能上有所保证?/p>

HTTP 文本方式Q和MQTT二进制之间需要某些规则的转换Qؓ了兼容,需要单独定义接口传输接口,ChannelEntryQ双通道和单通道处理数据的方式不同,单通道的HTTP JSONP需要支持短暂缓存消息ƈ{待客户端的依次获取。发?接收订阅消息ӞTCP/Websocket利用双通道对应Channel可直接发送?/p>

HTTP通道已经预留出接口,便于支持其它cd的HTTP传输通道Q比如需要在非浏览器环境中实现常规的long polling/Http StreamingQ仅仅需要做到实现相应接口即可?/p>

客户端ID的生成方式,一般是由服务器端生成的SessionId军_。传输纯文本方式比较l构化JSONl构比较合适?/p>

JSONP只支持HTTP GET方式Q这一炚w要牢记?/p>

传输接口定义

  1. q接获取授权 /jsonp/connect
  2. 订阅主题 /jsonp/subscribe
  3. {待订阅消息 /jsonp/waiting
  4. 发布主题 /jsonp/publish
  5. 退订主?/jsonp/unsubscrible
  6. 关闭q接 /jsonp/disconnect

要求q回的消息类型都是JSON字符串Ş式,订阅/发布的消息,一定要包含{id:10, msg:'具体消息内容'}cMjson字符丌Ӏ?/p>

单示?/h3>

一般传输的是文字内容,但具有结构化的,非json莫属。无论是走TCP方式二进制流q是JSONP传输的内容体Qjson都是不错的可l构化数据的选择?/p>

览器端jqueryQ支持jsonphQ这里有一个简单示范:

填写好地址Q自动执行连接,订阅Q接收消息,一个最单的Demo表现了其程?/p>

单实现jsonp形式的MQTT OVER HTTPQ做到文本和二进制彼此之间交换数据。M在纯HTTP环境下用MQTT协议Q是一个不错的选择?/p>

nieyong 2014-06-06 16:42 发表评论
]]>
MQTT协议W记之mqtt.io目Websocket协议支持http://www.aygfsteel.com/yongboy/archive/2014/05/26/414130.htmlnieyongnieyongMon, 26 May 2014 11:14:00 GMThttp://www.aygfsteel.com/yongboy/archive/2014/05/26/414130.htmlhttp://www.aygfsteel.com/yongboy/comments/414130.htmlhttp://www.aygfsteel.com/yongboy/archive/2014/05/26/414130.html#Feedback4http://www.aygfsteel.com/yongboy/comments/commentRss/414130.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/414130.html前言

MQTT协议专注于网l、资源受限环境,建立之初不曾考虑WEB环境Q倒也正常。虽然如此,但不代表它不适合HTML5环境?/p>

HTML5 Websocket是徏立在TCP基础上的双通道通信Q和TCP通信方式很类|适用于WEB览器环境。虽然MQTT基因层面选择了TCP作ؓ通信通道Q但我们d个编解码方式QMQTT Over Websocket也可以的?/p>

q样做的好处QMQTT的用范畴被扩展到HTML5、桌面端览器、移动端WebApp、Hybrid{,多了一些想像空间。这L来,无论是移动端Q还是WEB端,MQTT都会有自q使用I间?/p>

览器支?/h3>

话说Q现代化览器都已经支持WebsocketQ这里有一个所有浏览器支持列表Q?/p>

b84feb4f-ff91-45fc-9798-ce6f44e76af9

更详l列表,L接访问:http://caniuse.com/websockets

毫无疑问Q火狐和h览器带动了C览器的发展Q对HTML5标准的支持也是如此。支持Websocket的浏览器单纯从上面数字来Ԍ73.88%的支持率。但实际上还得参考浏览器市场占有率:

1[1]

上图数据Q来源于: 2014q?月䆾全球L览器市Z额排行榜

过60%用户机器上浏览器的支持WebsocketQ数据很可观?/p>

Udhybrid型应用会很欢qWebsocket

  • 内置览器支持HTML5QJavascript操作Websocketq接MQTT
  • 借助于原生TCP socket通道q接MQTT服务器,暴露JavaScript接口Q间接?

不支持Websocket的桌面浏览器Q可以考虑Flash socket来帮忙!

针对不支持websocker的部分历史浏览器Q可以考虑一下Flash socketQ虽然用Flashsocket用以模拟Websocket很Ҏ理解Q但条g如下Q?- 需要单独占用一个端口专用于安全跨域讉K{略 - 需要浏览器支持二进制Blob 支持二进制操作的览器现Ӟ

xhr2

来源于:http://caniuse.com/xhr2

比较一下支持Websocket和XHR2的桌面浏览器Q重叠率很高Q用Flash Socket用以模拟Websocket必要性不大,在类gIEq_上,不如直接使用Flash版本?/p>

https://github.com/yangboz/as3MQTT/tree/master/MQTTClient_AS3

不支持Websocket览器怎么?/h4>

不是所有浏览器都支持WebsocketQ尤其是ȝ历史发展的IE6/IE7/IE8/IE9。MQTT协议Zq制协议压根和HTTPU文本不兼容Q尤其浏览器端JavaScript处理文本很合适,但二q制显得笨手笨角,除非支持XHR2?/p>

  1. 单独使用Flash MQTT ClientQ这q方面见解不深,实践很少Q不便多_您要是很了解Q不妨告知一二?
  2. HTTPU文本方式进行二q制Ҏ

q部分后面专门会讲到?/p>

服务器端支持

现有一些解x案可能是后面为MQTT BrokerQ前面是d一层代理。比如:例如 mod_websocket Q对应在U示范:http://test.mosquitto.org/ws.html

表面上看着很解藕的Q实际上模仿的还是传l型的短q接反向代理架构QNginx/Apache QJava/PHP/Python/Ruby?/p>

客户端徏立一条连接,服务器端需要用到臛_两个文g句柄Q中间多了一层\径。优雅的解决ҎQ可以向socket.io看v。一套服务端E序Q同时提供若q种协议供终端选择。其实,一台MQTT Broker中间件服务器Q可以绑定多个端口,一个面向纯TCP?883端口Q一个面向Websocket?0/8080端口Q共享基逻辑Q面向不同协议?/p>

Websocket协议适配

服务器添加对Websocket支持Q基本不用做多大改动。对比Tcp的附加到单个Channel的处理器列表Q?

Websocket对应单个Channel的处理器列表Q?

Z支持Websocket协议Q仅仅额外增加了Q?

啰啰嗦嗦的讲了一大通WebsocketQM对Websocket的支持还容易。后面有旉写写如何使用HTTP协议辑ֈMQTT OVER HTTP的效果?/p>

nieyong 2014-05-26 19:14 发表评论
]]>
MQTT协议W记之mqtt.io目TCP协议支持http://www.aygfsteel.com/yongboy/archive/2014/05/24/414071.htmlnieyongnieyongSat, 24 May 2014 15:03:00 GMThttp://www.aygfsteel.com/yongboy/archive/2014/05/24/414071.htmlhttp://www.aygfsteel.com/yongboy/comments/414071.htmlhttp://www.aygfsteel.com/yongboy/archive/2014/05/24/414071.html#Feedback2http://www.aygfsteel.com/yongboy/comments/commentRss/414071.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/414071.html

前言

MQTT定义了物联网传输协议Q其标准們֐于原始TCP实现。构ZTCP的上层协议堆栈,诸如HTTP{,在空间上多了一些处理\径,E微耗费了CPU和内存,虽看似微乎其微,但对很多处理能力不的嵌入式讑֤而言Q选择原始的TCP却是最好的选择?/p>

但单UTCP不是所有物件联|的最佳选择Q提供构ZTCP基础之上的传l的HTTP通信支持Q尤其是览器、性能富裕的桌面涉及领域,q是企业最 可信赖、最可控的传输方式之一。支持多U多Lq接通道Q让目前所有一切皆可联|,除了原始TCP SocketQ还要支持构Z其之上的HTTP、HTML5 WebsocketQ就很有必要?/p>

mqtt.ioQPub/Sub中间Ӟ也可以称之ؓ推送服务器Q涵盖所有主桌面系l、浏览器q_Qƈ且倾斜 于移动互联网Q以及物联网的广阔适应天地。用一句英文概括可能更为合适:"Make everything connect”Q让所有物仉可连接。其业务目标Q可用下图概括:

mqtt.io致力于做下一代支持所有主桌面^台、所有主浏览器、所有可联网物g都可以联|的PUB/SUB消息推送系l?/p>

构徏此系l,在于降低传统企业各自分散的推送系l,l一q营Q统一理Q节省h员、运l开支?/p>

注意事项

  1. mqtt.io是一个项目名Uͼ没有官网Qhttp://www.mqtt.ioQ和q个目没有一毛钱关系?/li>
  2. 目地址Q?a >https://github.com/yongboy/mqtt.ioQ?/li>
  3. 目名称启发?http://socket.io http://netty.io {知名framework?/li>
  4. 目前只实现QoS 0基本Ҏ,实现概览Q后期会Ҏ反馈Q做Z些调?/li>

依赖

  1. netty 4Q目前JAVA IO界明?/li>
  2. mqtt-library 二进制和MQTT对象的{换,q种苦活累活都是它来做,真心让h喜欢?/li>

数据{

解码?/h4>

用于转换二进制流到JAVA对象的过E:

~码?/h4>

Ҏ有要写入|卡~冲区的JAVA对象转换成二q制Q?

借助于mqtt-library目Q编解码不复杂?/p>

MQTT的消息处?/h4>

更具体的可以查看目?/p>

单介l了一个简单的不能再简单的MQTT ServerQ只h最基本的QoS 0cd的消息订阅等?/p>

后面Q对HTML 5 WebsocketQ会在现有基代码之上Q不做多大改动,增加对MQTT Over WebSocket的支持?/p>

nieyong 2014-05-24 23:03 发表评论
]]>
MQTT协议W记之订?/title><link>http://www.aygfsteel.com/yongboy/archive/2014/04/12/412351.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Sat, 12 Apr 2014 08:03:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2014/04/12/412351.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/412351.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2014/04/12/412351.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/412351.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/412351.html</trackback:ping><description><![CDATA[     摘要: 前言 记忆不太好的时候,只能ȝ以前的文?W记重新温习一遍,但找不到MQTT协议有关订阅部分的描qͼ好不Ҏ从Evernote中找到脓出来Q这h个MQTT协议W记Q就比较齐全了?SUBSCRIBE 一般来Ԍ客户端在成功建立TCPq接之后Q发送CONNECT消息Q在得到服务器端授权允许建立彼此q接的CONNACK消息之后Q客L会发送SUBSCRIBE消息Q订阅感兴趣的Topic主题?..  <a href='http://www.aygfsteel.com/yongboy/archive/2014/04/12/412351.html'>阅读全文</a><img src ="http://www.aygfsteel.com/yongboy/aggbug/412351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2014-04-12 16:03 <a href="http://www.aygfsteel.com/yongboy/archive/2014/04/12/412351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT协议W记之消息流http://www.aygfsteel.com/yongboy/archive/2014/02/15/409893.htmlnieyongnieyongSat, 15 Feb 2014 11:17:00 GMThttp://www.aygfsteel.com/yongboy/archive/2014/02/15/409893.htmlhttp://www.aygfsteel.com/yongboy/comments/409893.htmlhttp://www.aygfsteel.com/yongboy/archive/2014/02/15/409893.html#Feedback8http://www.aygfsteel.com/yongboy/comments/commentRss/409893.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/409893.html前言

前面的笔记已把所有消息类型都q了一遍,q里从消息流的角度尝试解M下?/p>

|络故障

在Q何网l环境下Q都会出C方连接失败,比如d公司大门那一L有了WIFI信号。但持箋q接的另一?服务器可能不能立即知道对方已断开。类似网l异常情况,都有可能在消息发送的q程中出玎ͼ消息发送出去,׃׃?/p>

MQTT协议假定客户端和服务器端E_情况一般,彼此之通信道不可靠,一旦客L|络断开Q情况就会很严重Q很难恢复原状?/p>

但别忘记Q很多客L会有怹性存储设备支持,比如闪存ROM、存储卡{,在通信出现异常的情况下可以用于保存关键数据或状态信息等?/p>

MQ异常网l情况很复杂Q只能小心处理之?/p>

消息重发{略

?strong>QoS > 0情况下,PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE{类型消息在发送者发送完之后Q需要等待一个响应消息,若在一个指定时间段内没有收刎ͼ发送者可能需要重试。重发的消息Q要求DUP标记要设|ؓ1.

{待响应的超时应该在消息成功发送之后开始算Pq且{待时应该是可以配|选项Q以便在下一ơ重试的时候,适当加大。比如第一ơ重试超?0U,下一ơ可能ؓ20U,再一ơ重试可能ؓ60U呢。当Ӟq要有一个重试次数限制的?/p>

q有一U情况,客户端重新连接,但未在可变头部中讄clean session标记Q但双方(客户端和服务器端)都应该重试先前未发送的动态消息(in-flight messagesQ。客L不被强制要求发送未被确认的消息Q但服务器端得需要重发那些未被去认的消息?/p>

QoS level军_的消息流

QoS level为Quality of Service level的羃写,译成中文,服务质量{?/p>

MQTT 3.1协议?4.1 Quality of Service levels and flows"章节中,仅仅讨论了客L到服务器的发布流E,不太完整。因为决定消息到辄Q能够提升发送质量的Q应该是服务器发布PUBLISH消息到订阅者这一消息方向?/p>

QoS level 0

臛_发送一ơ,发送即丢弃。没有确认消息,也不知道Ҏ是否收到?/p>
Client Message and direction Server
QoS = 0 PUBLISH
---------->
Action: Publish message to subscribers then Forget
Reception: <=1

针对的消息不重要Q丢׃无所谓?/p>

|络层面Q传输压力小?/p>

QoS level 1

所有QoS level 1都要在可变头部中附加一?6位的消息ID?/p>

SUBSCRIBE和UNSUBSCRIBE消息使用QoS level 1?/p>

针对消息的发布,Qos level 1Q意味着消息臛_被传输一ơ?/p>

发送者若在一D|间内接收不到PUBACK消息Q发送者需要打开DUB标记?Q然后重新发送PUBLISH消息。因此会D接收方可能会收到两次PUBLISH消息。针对客L发布消息到服务器的消息流Q?/p>
Client Message and direction Server
QoS = 1
DUP = 0
Message ID = x

Action: Store message

PUBLISH
---------->
Actions:
  • Store message

  • Publish message to subscribers
  • Delete message

Reception: >=1
Action: Discard message PUBACK
<----------
Message ID = x

针对服务器发布到订阅者的消息:

Server Message and direction Subscriber
QoS = 1
DUP = 0
Message ID = x
PUBLISH
---------->
Actions:
  • Store message

  • Make message available                       
Reception: >=1

PUBACK
<----------
Message ID = x

发布者(客户?服务器)若因U种异常接收不到PUBACK消息Q会再次重新发送PUBLISH消息Q同时设|DUP标记?。接收者以服务器ؓ例,q可能会D服务器收到重复消息,按照程QbrokerQ服务器Q发布消息到订阅者(会导致订阅者接收到重复消息Q,然后发送一条PUBACK认消息到发布者?/p>

在业务层面,或许可以弥补MQTT协议的不之处:重试的消息ID一定要一致接收方一定判断当前接收的消息ID是否已经接受q?/p>

但一样不能够完全保Q消息一定到达了?/p>

QoS level 2

仅仅在PUBLISHcd消息中出玎ͼ要求在可变头部中要附加消息ID?/p>

U别高,通信压力E大些,但确保了仅仅传输接收一ơ?/p>

先看协议中流E图QClient -> Server方向Q会有一个M印象Q?/p>
Client Message and direction Server
QoS = 2
DUP = 0
Message ID = x

Action: Store message

PUBLISH
---------->
Action(a) Store message

or

Actions(b):
  • Store message ID
  • Publish message to subscribers
  PUBREC
<----------
Message ID = x
Message ID = x PUBREL
---------->
Actions(a):
  • Publish message to subscribers
  • Delete message

or

Action(b): Delete message ID
Action: Discard message PUBCOMP
<----------
Message ID = x

Server -> SubscriberQ?/p>
Server Message and direction Subscriber
QoS = 2
DUP = 0
Message ID = x
PUBLISH
---------->
Action: Store message
  PUBREC
<----------
Message ID = x
Message ID = x PUBREL
---------->
Actions:
  • Make message available                       

PUBCOMP
<----------
Message ID = x

Server端采取的Ҏa和bQ都包含了何时消息有效,何时处理消息。两个方案二选一QServer端自己决定。但无论死采取哪一U方式,都是在QoS level 2协议范畴下,不受影响。若一Ҏ有接收到对应的确认消息,会从最q一ơ需要确认的消息重试Q以便整个(QoS level 2Q流E打通?/p>

消息序

消息序会受许多因素的媄响,但对于服务器E序Q必M证消息传递流E的每个阶段要和开始的序一致。例如,在QoS level 2定义的消息流中,PUBREL必dPUBLISH具有相同的序发送:

Client Message and direction Server
  PUBLISH 1
---------->
PUBLISH 2
---------->
PUBLISH 3
---------->
 
  PUBREC 1
<----------
PUBREC 2
<----------
 
  PUBREL 1
---------->
 
  PUBREC 3
<----------
 
  PUBREL 2
---------->
 
  PUBCOMP 1
<----------
 
  PUBREL 3
---------->
 
  PUBCOMP 2
<----------
PUBCOMP 3
<----------
 

动消息(in-flight messages)数量允许有一个可保证的效果:

  • 在流动消?in-flight)H口1中,每个传递流在下一个流开始之前完成。这保证消息以提交的序传?
  • 在流动消?in-flight)大于1的窗口,只能在QoS level内被保证消息的顺?

消息的持久化

在MQTT协议中,PUBLISH消息固定头部RETAIN标记Q只有ؓ1才要求服务器需要持久保存此消息Q除非新的PUBLISH覆盖?/p>

对于持久的、最C条PUBLISH消息Q服务器不但要发送给当前的订阅者,q且新的订阅?new subscriberQ同样需要订阅了此消息对应的Topic nameQ会马上得到推送?/p>

TipQ新来乍到的订阅者,只会取出最新的一个RETAIN flag = 1的消息推送,不是所有?

消息的~码/解码

MQTT协议中,q前定义的14U类型消息在客户端和服务器端之间数据q行交互。若以JAVA语言构徏MQTT服务器,可选择Netty作ؓ基础?/p>

在Netty中,数据的进入和出Q代表了一ơ完整的交互。无论是要进入的q是要流出的数据(单独以服务器Z)Q都可看做字节流。若把每U类型消息抽象ؓ一个具体对象,那么处理h׃难了?/p>

客户?>服务器,q入的字节流Q逐个字节/单位dQ可q原成一个具体的消息对象Q解码的q程Q?/p>

要发送到客户端的消息对象Q{换(~码Q成字节,然后由TCP通道{到接收者?/p>

断断l箋记录了MQTT 3.1协议的若q阅ȝ讎ͼM是把协议个h认ؓ不够清晰Q或者我不好理解的地方,着重进行了分析。也便于自己以后回过来头来翻阅,不是那么快的忘却?/p>

nieyong 2014-02-15 19:17 发表评论
]]>
MQTT协议W记之发布流E?/title><link>http://www.aygfsteel.com/yongboy/archive/2014/02/10/409689.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 10 Feb 2014 15:42:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2014/02/10/409689.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/409689.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2014/02/10/409689.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/409689.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/409689.html</trackback:ping><description><![CDATA[<h2>前言</h2> <p>q次要讲到客L/服务器的发布消息行ؓQ与PUBLISH相关的消息类型,会在q里看到?/p> <h2>PUBLISH</h2> <p>客户端发布消息经由服务器分发到所有对应的订阅者那里。一个订阅者可以订阅若q个主题(Topic name)Q但一个PUBLISH消息只能拥有一个主题?/p> <p>消息架构一览:</p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; width: 800px; font-family: Verdana, Arial, Helvetica, sans-serif;" width="924"> <thead> <tr> <th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="101"> </th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="235">Description</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="48">7</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="42">6</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="43">5</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="42">4</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="81">3</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="40">2</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="53">1</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="71">0</th> </tr> </thead> <tbody> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Fixed header/固定头部</strong></td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="4" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Message Type(3)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">DUP flag</td> <td colspan="2" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">QoS level</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">RETAIN</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Remaining Length</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Variable header</strong>/可变头部</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">Topic name</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Length MSB (0)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Length LSB (3)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 3</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">'a' (0x61)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 4</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">'/' (0x2F)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 5</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">'b' (0x62)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">Message Identifier</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 6</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID MSB (0)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 7</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID LSB (10)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Playload/消息?/strong></td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">BLOBQ二q制对象形式。二q制具体包含的内容和格式Q可有应用程序自w定义。若消息体ؓI?0长度)也是可能的?/td> </tr> </tbody> </table> <h3>固定头部</h3> <p>DUP flagQ设?Q表C当前ؓW一ơ发送?/p> <p>RETAIN flagQ只有在PUBLISH消息中才有效?/p> <ul> <li>1Q表C发送的消息需要一直持久保存,不但要发送给当前的订阅者,q且以后新来的订阅了此Topic name的订阅者会马上得到推送? 备注Q新来乍到的订阅者,只会取出最新的一个RETAIN flag = 1的消息推送,不是所有?/li> <li>0Q仅仅ؓ当前订阅者推送此消息?</li> </ul> <h3>可变头部</h3> <p>Topic nameQUTF-8~码字符串Ş式,不支持通配W!</p> <h3>消息?/h3> <p>一般作为UTF-8~码写入接口Q但不排除自定义的消息格式?/p> <p>I的消息体(zero-lengthQ的PUBLISH消息也可以是合法的?/p> <p>当服务器接收到空消息?zero-length payload)、retain = 1、具有topic name的一个PUBLISHҎ消息Q表C同时满retain = 1、相同topic name的这两个特征的被持久化PUBLISH消息Q可被删除?/p> <h3>Response/响应</h3> <p>固定头部QoS level军_了消息中间g针对发布者具体需要响应的内容Q?/p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"> <thead> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS Level</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Expected response</td> </tr> </thead> <tbody> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS 0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">None</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">PUBACK</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">PUBREC</td> </tr> </tbody> </table> <p>备注Q仅仅针对发布PUBLISH消息的发布者?/p> <h3>Actions:</h3> <p>无论是订阅者还是服务器接收到PUBLISH消息之后Q需要根据QoS level执行不同动作?/p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; font-family: Verdana, Arial, Helvetica, sans-serif;"> <thead> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS Level</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Expected Action</td> </tr> </thead> <tbody> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS 0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">发送到所有感兴趣?/td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">持久化记录下来,发送到所有感兴趣的参与者,q回一个PUBACK消息l发送?/td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">QoS 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">持久化记录下来,暂时不发送所有感兴趣的参与者,q回一个PUBREC消息l发送?/td> </tr> </tbody> </table> <p>如果服务器收到PUBLISH消息Q参与者指的是订阅者。如果订阅者收到PUBLISH消息Q参与者就是服务器? 需要注意:</p> <ol> <li>发布者发布的PUBLISH消息发送到服务器,在payload/消息体处可能夹带有私货,可能含有自定义的数据 格式</li> <li>若兼容MQTT客户端,l由服务器分发到所有对应订阅者处只能是规规矩矩的PUBLISH消息Qƈ且固定头部的RETAIN标志不能被设|成有效?</li> </ol> <h3>授权</h3> <p>未经授权的发布者提交的PUBLISH消息Q服务器会忽略掉Q客L不会被通知?/p> <h2>PUBACK</h2> <p>作ؓ订阅?服务器接ӞQoS level = 1QPUBLISH消息之后对发送者的响应Q整个消息不复杂?/p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; font-family: Verdana, Arial, Helvetica, sans-serif;"> <thead> <tr> <th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="101"> </th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="235">Description</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="48">7</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="47">6</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="50">5</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="42">4</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="81">3</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="59">2</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="53">1</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="71">0</th> </tr> </thead> <tbody> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Fixed header/固定头部</strong></td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="4" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Message type (4)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">DUP flag</td> <td colspan="2" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">QoS flags</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">RETAIN</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="8" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Remaining Length (2)</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Variable header</strong>/可变头部</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">Message Identifier</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID MSB (0)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID LSB (10)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> </tbody> </table> <p>虽没有消息体Q但可变头部附加一?6位的无符号shortcd?/p> <h2>PUBREC</h2> <p>字面意思ؓAssured publish receivedQ作阅?服务器对QoS level = 2的发布PUBLISH消息的发送方的响应,认已经收到QؓQoS level = 2消息的W二个消息? 和PUBACK相比Q除了消息类型不同外Q其它都是一栗?/p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; width: 800px; font-family: Verdana, Arial, Helvetica, sans-serif;"> <thead> <tr> <th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="101"> </th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="235">Description</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="48">7</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="47">6</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="50">5</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="42">4</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="50">3</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="59">2</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="53">1</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="71">0</th> </tr> </thead> <tbody> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Fixed header/固定头部</strong></td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="4" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Message type (5)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">DUP flag</td> <td colspan="2" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">QoS flags</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">RETAIN</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="8" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Remaining Length (2)</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Variable header</strong>/可变头部</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">Message Identifier</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID MSB (0)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID LSB (10)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> </tbody> </table> <p>无论是订阅者还是服务器Q在消费PUBREC消息之后需要发送一个PUBREL消息l发送者(和PUBRECh同样的消息IDQ,认已收到?/p> <h2>PUBREL</h2> <p>Qos level = 2的协议流的第三个消息Q有PUBLISH消息的发布者发送,参与Ҏ收。完整示范如下:</p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; font-family: Verdana, Arial, Helvetica, sans-serif;"> <thead> <tr> <th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="101"> </th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="235">Description</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="48">7</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="47">6</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="50">5</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="42">4</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="81">3</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="59">2</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="53">1</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="71">0</th> </tr> </thead> <tbody> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Fixed header/固定头部</strong></td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="4" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Message type (6)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">DUP flag</td> <td colspan="2" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">QoS flags</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">RETAIN</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="8" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Remaining Length (2)</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Variable header</strong>/可变头部</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">Message Identifier</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID MSB (0)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID LSB (10)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> </tbody> </table> <p>QoS level 1QPUBREL消息要求如此?/p> <p>DUP flag ?Q表C消息第一ơ被发送?/p> <p>毫无疑问Q剩余长度ؓ2个byte长度?/p> <p>可变头部中,消息ID和发布者接收到的PUBREC所包含的消息ID是一致的?/p> <h3>动作Q?/h3> <ol> <li>服务器接收到发布者(aQ的PUBREL消息Q此时服务器让发布者(aQ刚才发布PUBLISH消息可用Q发送此PUBLISH消息l所有订阅此主题的订阅者,然后发送PUBCOMP消息l发布者(aQ?/li> <li> 可变头部包含消息ID和服务器接收的PUBREL消息ID是一致的? 一个订阅者接收到PUBREL消息Q订阅者PUBLISH消息可用Q然后反馈一个PUBCOMP消息l服务器 </li> </ol> <h2>PUBCOMP</h2> <p>作ؓQoS level = 2消息第四个Q也是最后一个消息,由收到PUBREL的一方向另一方做出的响应消息?/p> <p>完整的消息一览,和PUBREL一_除了消息cd?/p> <table style="margin-left: 3em; empty-cells: show; border-collapse: collapse; border: 1px solid black; font-family: Verdana, Arial, Helvetica, sans-serif;"> <thead> <tr> <th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="101"> </th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" width="235">Description</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="48">7</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="47">6</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="50">5</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="42">4</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="81">3</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="59">2</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="53">1</th><th colspan="1" rowspan="1" style="background-color: #dedeff; border: 1px solid black; padding: 5px;" align="center" width="71">0</th> </tr> </thead> <tbody> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Fixed header/固定头部</strong></td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="4" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Message type (7)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">DUP flag</td> <td colspan="2" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">QoS flags</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">RETAIN</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">x</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="8" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">Remaining Length (2)</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;"> </td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;"><strong>Variable header</strong>/可变头部</td> </tr> <tr> <td colspan="10" rowspan="1" style="border: 1px solid black; padding: 5px;">Message Identifier</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID MSB (0)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> <tr> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">byte 2</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;">Message ID LSB (10)</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">1</td> <td colspan="1" rowspan="1" style="border: 1px solid black; padding: 5px;" align="center">0</td> </tr> </tbody> </table> <p>当客L接收一个PUBCOMP消息Ӟ客户端摒弃原来的消息Q因为它已经成功发送消息到服务器?/p> <h2>结</h2> <p>消息的发布和认{一些流E,主要是跟消息发布者所讑֮的QoS level有关Q稍加整理,l制了下面一张图Q理解v来可能会更清CQ?/p> <p><img src="http://images.blogjava.net/blogjava_net/yongboy/Documents.png" alt="Publish程? width="832" /></p> <p>上图针对的是客户端发布消息到服务器端的方向?/p> <p>Z保消息已经成功传递过去,只有收到了确认,才会让h特别攑ֿ?/p> <p>在QoS level = 2Ӟ通信双方都需要知道各自的认程以及所处阶D늭Q交互很多,数据量大的情况下Q可能会造成数据U\传递拥塞。服务器选择QoS = 0/1Q大部分情况都是可以应对的? 比如重要消息Q就要确保对斚w要收刎ͼ然后彼此认QOKQ这个消息是真实、有效的?/p> <p>无论Qos level??Q还?Q服务器Q具备所有条仉满之后Q总要把收到的具体内容和topicl装成一个新的PUBLISH MessageQ也不一定要重新构造,但要求推送的PUBLISH消息Q一定要h明确的主题和内容QRETAIN标志不能讄?Q推送到所有感兴趣的订阅者?/p> <p>嗯,消息的发布来源别忘记q有可能来自CONNECT消息中的Will Topic和Will MessageQ若是设|了Will flag标记的话?/p><img src ="http://www.aygfsteel.com/yongboy/aggbug/409689.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2014-02-10 23:42 <a href="http://www.aygfsteel.com/yongboy/archive/2014/02/10/409689.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MQTT协议W记之连接和心蟩http://www.aygfsteel.com/yongboy/archive/2014/02/09/409630.htmlnieyongnieyongSun, 09 Feb 2014 05:41:00 GMThttp://www.aygfsteel.com/yongboy/archive/2014/02/09/409630.htmlhttp://www.aygfsteel.com/yongboy/comments/409630.htmlhttp://www.aygfsteel.com/yongboy/archive/2014/02/09/409630.html#Feedback6http://www.aygfsteel.com/yongboy/comments/commentRss/409630.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/409630.html阅读全文

nieyong 2014-02-09 13:41 发表评论
]]>
MQTT协议W记之头部信?/title><link>http://www.aygfsteel.com/yongboy/archive/2014/02/07/409587.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 07 Feb 2014 09:35:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2014/02/07/409587.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/409587.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2014/02/07/409587.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/409587.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/409587.html</trackback:ping><description><![CDATA[     摘要: 前言 MQTTQMessage Queue Telemetry TransportQ?遥测传输协议Q提供订?发布模式Q更为简U、轻量,易于使用Q针对受限环境(带宽低、网lgq高、网l通信不稳定)Q可以简单概括ؓ物联|打造,官方ȝ特点如下Q?.使用发布/订阅消息模式Q提供一对多的消息发布,解除应用E序耦合?2. 对负载内容屏蔽的消息传输?3. 使用 TCP/IP 提供|络q接?4. ...  <a href='http://www.aygfsteel.com/yongboy/archive/2014/02/07/409587.html'>阅读全文</a><img src ="http://www.aygfsteel.com/yongboy/aggbug/409587.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2014-02-07 17:35 <a href="http://www.aygfsteel.com/yongboy/archive/2014/02/07/409587.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ԭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ຣʡ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ͻ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">׼</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽʡ</a>| <a href="http://" target="_blank">Ľ</a>| <a href="http://" target="_blank">齭</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Դ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ף</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ﴨ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">˳</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">綫</a>| <a href="http://" target="_blank">ƽԶ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ѿ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>