前言
MQTT协议诞生之初,就未曾考虑通过HTTP传输。这也正常,网络受限、不稳定网络不太适合HTTP(2G/3G网络大家使用WAP不也OK嘛)。在网络较为充裕的桌面端而言,虽纯文本对比二进制而言没多大优势,受制于历史遗留和使用习惯,以及一大票传统基础设施方便控制事宜,传统互联网/企业型应用,HTTP协议都是默认最佳选择,安全可控,人机友好。选择HTTP也在情理之中。
虽桌面端日渐式微,但做统一的全平台化消息系统/消息中间件,也是趋势。
MQTT OVER HTTP,为WEB环境提供HTTP通道协议支持,在统一平台化这样的考量下,就显得合情合理。 MQTT相比其它基于HTTP的交换协议而言(比如socket.io),流量节省,消息质量可控。
一句话,比它强大的,没有它轻量。比它还轻的,没有它可控。
总之,在资源受限环境下表现如此优异,那么桌面端会表现的更为优秀。
HTTP支持情况
二进制支持,针对浏览器端Javascript而言,处理起来,如同在石器时代要处理工业时代一些通讯方式,非常吃力。支持Javascript二进制操作的浏览器现状:
来源于:http://caniuse.com/xhr2
这和支持Websocket的浏览器的基本重叠。
要想让HTTP传输MQTT具体消息二进制,然后由浏览器Javascript脚本进行解析,无法做到支持所有常见浏览器,需要考虑纯文本方式的传输。
设计摘要
AJAX方式,支持跨域,支持所有主流平台,桌面+移动设备;所有浏览器,移动的,桌面的,包括IE6+。那么最理想方式就是JSONP,基于文本通信的Long-polling JSONP方式。
MQTT 协议关键交互点: 1. 连接获取授权 1. 订阅/退订主题 1. 发布消息 1. 等待订阅消息 1. 关闭连接
若支持HTTP方式完成以上功能/步骤,服务器端需要支持接收HTTP纯文本内容请求,拼装、转换成Java对象,业务层面实现数据流转、交换,直接插入到更具体业务中,这样就很容易。虽类似于桥接,但减少了桥接的路径(HTTP —》MQTT),减少资源占用,性能上有所保证。
HTTP 文本方式,和MQTT二进制之间需要某些规则的转换,为了兼容,需要单独定义接口传输接口,ChannelEntry,双通道和单通道处理数据的方式不同,单通道的HTTP JSONP需要支持短暂缓存消息并等待客户端的依次获取。发布/接收订阅消息时,TCP/Websocket利用双通道对应Channel可直接发送。
HTTP通道已经预留出接口,便于支持其它类型的HTTP传输通道,比如需要在非浏览器环境中实现常规的long polling/Http Streaming,仅仅需要做到实现相应接口即可。
客户端ID的生成方式,一般是由服务器端生成的SessionId决定。传输纯文本方式比较结构化JSON结构比较合适。
JSONP只支持HTTP GET方式,这一点需要牢记。
传输接口定义
- 连接获取授权 /jsonp/connect
- 订阅主题 /jsonp/subscribe
- 等待订阅消息 /jsonp/waiting
- 发布主题 /jsonp/publish
- 退订主题 /jsonp/unsubscrible
- 关闭连接 /jsonp/disconnect
要求返回的消息类型都是JSON字符串形式,订阅/发布的消息,一定要包含{id:10, msg:‘具体消息内容‘}类似json字符串。
简单示范
一般传输的是文字内容,但具有结构化的,非json莫属。无论是走TCP方式二进制流还是JSONP传输的内容体,json都是不错的可结构化数据的选择。
浏览器端jquery,支持jsonp请求,这里有一个简单示范:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
<html>
<head>
<meta charset="UTF-8">
<title>jsonp exampletitle>
<script src="http://libs.baidu.com/jquery/1.5.0/jquery.js">script>
<script type="text/Javascript">
var clientId = "";
var urlPrefix = "http://127.0.0.1:8080/jsonp";
$(document).ready(function(){
doConnect();
});
function doConnect(){
jreq(urlPrefix + ‘/connect‘, ‘‘, function(data){
if(data.status){
log("connected!");
clientId = data.clientId;
doSub();
}else{
alert("failure !");
}
});
}
function doSub(){
jreq(urlPrefix + ‘/subscribe‘, ‘topic=sub-msg/webclient1‘, function(data){
if(data.status){
log("subscribed!");
doWaiting();
}else{
log("bad!");
}
});
}
function doWaiting(){
jreq(urlPrefix + ‘/waiting‘, ‘‘, function(data){
log("Got Message : id = " + data.id + " msg = " + data.msg);
doWaiting();
});
}
function jreq(url, parameter, fn){
$.ajax({
url:url,
dataType:"jsonp",
jsonp:"jsonpcallback",
data: parameter,
timeout: 300000,
async:true,
success:function(data){
fn(data);
}
});
}
function log(val){
$("#log").html(val + " " + $("#log").html());
}
script>
head>
<body>
<div id="log">div>
body>
html>
|
view rawjsonp.html hosted with ? by GitHub
填写好地址,自动执行连接,订阅,接收消息,一个最简单的Demo表现了其流程。
小结
简单实现jsonp形式的MQTT OVER HTTP,做到文本和二进制彼此之间交换数据。总之在纯HTTP环境下使用MQTT协议,是一个不错的选择。
原文 http://www.blogjava.net/yongboy/archive/2014/06/06/414474.html
MQTT协议笔记之mqtt.io项目HTTP协议支持