MQTT协议笔记之mqtt.io项目TCP协议支持
前言
MQTT定义了物联网传输协议,其标准倾向于原始TCP实现。构建于TCP的上层协议堆栈,诸如HTTP等,在空间上多了一些处理路径,稍微耗费了CPU和内存,虽看似微乎其微,但对很多处理能力不足的嵌入式设备而言,选择原始的TCP却是最好的选择。
但单纯TCP不是所有物件联网的最佳选择,提供构建与TCP基础之上的传统的HTTP通信支持,尤其是浏览器、性能富裕的桌面涉及领域,还是企业最 可信赖、最可控的传输方式之一。支持多种多样的连接通道,让目前所有一切皆可联网,除了原始TCP Socket,还要支持构建于其之上的HTTP、HTML5 Websocket,就很有必要。
mqtt.io,Pub/Sub中间件,也可以称之为推送服务器,涵盖所有主流桌面系统、浏览器平台,并且倾斜 于移动互联网,以及物联网的广阔适应天地。使用一句英文概括可能更为合适:"Make everything connect”,让所有物件都可连接。其业务目标,可用下图概括:
mqtt.io致力于做下一代支持所有主流桌面平台、所有主流浏览器、所有可联网物件都可以联网的PUB/SUB消息推送系统。
构建此系统,在于降低传统企业各自分散的推送系统,统一运营,统一管理,节省人员、运维开支。
注意事项
- mqtt.io是一个项目名称,没有官网,http://www.mqtt.io,和这个项目没有一毛钱关系。
- 项目地址:https://github.com/yongboy/mqtt.io,
- 项目名称启发于 http://socket.io http://netty.io 等知名framework。
- 目前只实现QoS 0基本特性,实现概览,后期会根据反馈,做出一些调整
依赖
- netty 4,目前JAVA IO界明星
- mqtt-library 二进制和MQTT对象的转换,这种苦活累活都是它来做,真心让人喜欢。
数据流转
解码器
用于转换二进制流到JAVA对象的过程:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 |
package io.mqtt.handler.coder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.io.ByteArrayInputStream;
import java.util.List;
import org.meqantt.message.Message;
import org.meqantt.message.MessageInputStream;
public class MqttMessageNewDecoder extends MessageToMessageDecoder<ByteBuf> {
@Override
public void decode(ChannelHandlerContext ctx, ByteBuf buf,
List<Object> out) throws Exception {
if (buf.readableBytes() < 2) {
return;
}
buf.markReaderIndex();
buf.readByte(); // read away header
int msgLength = 0;
int multiplier = 1;
int digit;
int lengthSize = 0;
do {
lengthSize++;
digit = buf.readByte();
msgLength += (digit & 0x7f) * multiplier;
multiplier *= 128;
if ((digit & 0x80) > 0 && !buf.isReadable()) {
buf.resetReaderIndex();
return;
}
} while ((digit & 0x80) > 0);
if (buf.readableBytes() < msgLength) {
buf.resetReaderIndex();
return;
}
byte[] data = new byte[1 + lengthSize + msgLength];
buf.resetReaderIndex();
buf.readBytes(data);
MessageInputStream mis = new MessageInputStream(
new ByteArrayInputStream(data));
Message msg = mis.readMessage();
mis.close();
out.add(msg);
}
}
|
编码器
对所有要写入网卡缓冲区的JAVA对象转换成二进制:
12345678910111213141516171819202122232425 |
package io.mqtt.handler.coder;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.List;
import org.meqantt.message.Message;
@Sharable
public class MqttMessageNewEncoder extends MessageToMessageEncoder<Object> {
@Override
protected void encode(ChannelHandlerContext ctx, Object msg,
List<Object> out) throws Exception {
if (!(msg instanceof Message)) {
return;
}
byte[] data = ((Message) msg).toBytes();
out.add(Unpooled.wrappedBuffer(data));
}
}
|
借助于mqtt-library项目,编解码不复杂。
MQTT的消息处理
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
package io.mqtt.handler;
import io.mqtt.processer.ConnectProcesser;
import io.mqtt.processer.DisConnectProcesser;
import io.mqtt.processer.PingReqProcesser;
import io.mqtt.processer.Processer;
import io.mqtt.processer.PublishProcesser;
import io.mqtt.processer.SubscribeProcesser;
import io.mqtt.processer.UnsubscribeProcesser;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.ReadTimeoutException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.meqantt.message.ConnAckMessage;
import org.meqantt.message.ConnAckMessage.ConnectionStatus;
import org.meqantt.message.DisconnectMessage;
import org.meqantt.message.Message;
import org.meqantt.message.Message.Type;
import org.meqantt.message.PingRespMessage;
public class MqttMessageHandler extends ChannelInboundHandlerAdapter {
private static PingRespMessage PINGRESP = new PingRespMessage();
private static final Map<Message.Type, Processer> processers;
static {
Map<Message.Type, Processer> map = new HashMap<Message.Type, Processer>(
6);
map.put(Type.CONNECT, new ConnectProcesser());
map.put(Type.PUBLISH, new PublishProcesser());
map.put(Type.SUBSCRIBE, new SubscribeProcesser());
map.put(Type.UNSUBSCRIBE, new UnsubscribeProcesser());
map.put(Type.PINGREQ, new PingReqProcesser());
map.put(Type.DISCONNECT, new DisConnectProcesser());
processers = Collections.unmodifiableMap(map);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable e)
throws Exception {
try {
if (e.getCause() instanceof ReadTimeoutException) {
ctx.write(PINGRESP).addListener(
ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
ctx.channel().close();
}
} catch (Throwable t) {
t.printStackTrace();
ctx.channel().close();
}
e.printStackTrace();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object obj)
throws Exception {
Message msg = (Message) obj;
Processer p = processers.get(msg.getType());
if (p == null) {
return;
}
Message rmsg = p.proc(msg, ctx);
if (rmsg == null) {
return;
}
if (rmsg instanceof ConnAckMessage
&& ((ConnAckMessage) rmsg).getStatus() != ConnectionStatus.ACCEPTED) {
ctx.write(rmsg).addListener(ChannelFutureListener.CLOSE);
} else if (rmsg instanceof DisconnectMessage) {
ctx.write(rmsg).addListener(ChannelFutureListener.CLOSE);
} else {
ctx.write(rmsg).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
}
|
更具体的可以查看项目。
小结
简单介绍了一个简单的不能再简单的MQTT Server,只具有最基本的QoS 0类型的消息订阅等。
后面,对HTML 5 Websocket,会在现有基础代码之上,不做多大改动,增加对MQTT Over WebSocket的支持。
MQTT协议笔记之mqtt.io项目TCP协议支持的更多相关文章
- MQTT协议笔记之mqtt.io项目Websocket协议支持
前言 MQTT协议专注于网络.资源受限环境,建立之初不曾考虑WEB环境,倒也正常.虽然如此,但不代表它不适合HTML5环境. HTML5 Websocket是建立在TCP基础上的双通道通信,和TCP通 ...
- MQTT学习笔记——Yeelink MQTT维修 采用mqtt.js和paho-mqtt
0 前言 2014年8月yeelink推出基于MQTT协议的开关类型设备控制API.相比于基于HTTP RESTful的轮训方式,通过订阅相关主题消息,能够远程控制类应用实时性更好. 本文使用 ...
- 学习笔记——网络编程3(基于TCP协议的网络编程)
TCP协议基础 IP协议是Internet上使用的一个关键协议,它的全称是Internet Protocol,即Internet协议,通常简称IP协议. 使用ServerSocket创建TCP服务 ...
- <再看TCP/IP第一卷>TCP/IP协议族中的最压轴戏----TCP协议及细节
题外话:刚刚过去的半个月实在是忙得我喘不过来气,虽然手里还压着几个项目得在期末考试之前做完,但是想想还是更新一下随笔,稍微换个心情.另外小吐槽一下那些在博客园里原封不动抄书当随笔的人,唉真是....算 ...
- MQTT协议笔记之mqtt.io项目HTTP协议支持
前言 MQTT协议诞生之初,就未曾考虑通过HTTP传输.这也正常,网络受限.不稳定网络不太适合HTTP(2G/3G网络大家使用WAP不也OK嘛).在网络较为充裕的桌面端而言,虽纯文本对比二进制而言没多 ...
- TCP协议系列之一一什么是TCP协议,TCP的三次握手,为什么不是2次或4次?
CP 为什么三次握手而不是两次握手(正解版) https://blog.csdn.net/lengxiao1993/article/details/82771768 自己理解说明一下: 比如说有一条管 ...
- Java基础知识强化之网络编程笔记06:TCP之TCP协议发送数据 和 接收数据
1. TCP协议发送数据 和 接收数据 TCP协议接收数据:• 创建接收端的Socket对象• 监听客户端连接.返回一个对应的Socket对象• 获取输入流,读取数据显示在控制台• 释放资源 TCP协 ...
- TCP/IP协议原理与应用笔记07:HTTP、TCP/IP与socket区别
1. TCP/IP协议与HTTP协议区别: HTTP 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件 ...
- (2)socket的基础使用(基于TCP协议)
socket()模块函数用法 基于TCP协议的套接字程序 netstart -an | findstr 8080 #查看所有TCP和UDP协议的状态,用findstr进行过滤监听8080端口 服务端套 ...
随机推荐
- Java中 堆 栈,常量池等概念解析(转载)
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符 ...
- rp2833 网卡以及串口与接插件位置关系
P13 eth0 (电口--兼容光口,如果使用光口,请将去掉U31以及P13) p12 eth1 P9 /dev/ttyS3 调试口 P10-1 /dev/ttyS2 r ...
- centos7 firewalled
FirewallD 使用服务(service) 和区域(zone)来代替 iptables 的规则(rule)和链(chain). 默认情况下,有以下的区域(zone)可用: drop – 丢弃所有传 ...
- FTP原理
1.1.1 ftp的主动模式和被动模式 扩展重要. FTP是仅基于TCP的服务,不支持UDP. 与众不同的是FTP使用2个端口,一个数据端口和一个命令端口(也可叫做控制端口).通常来说这两个端口是21 ...
- 打开Win7休眠模式和离开模式的方法
打开Win7休眠模式和离开模式的方法 ●启动休眠模式 从开始菜单中找到“附件→命令提示符”,手工输入如下命令:powercfg -a,从这里可以清楚的看到,计算机是支持休眠的,显示“尚未启用休眠&qu ...
- easyUI datagrid 排序
easyUI datagrid 排序 1.首先设置datagrid属性sortName 2.设置sortOrder 3.设置remoteSort(注:此属性默认为true,如果如果是对本地数据排序必须 ...
- 在CentOS上以源码编译的方式安装Greenplum数据库
集群组成: 一台主机,一台从节点. 系统环境: 操作系统:CentOS 7,64位,7.4.1708(/etc/redhat-release中查看) CPU:AMD Fx-8300 8核 内存:8GB ...
- qt 窗口控件自动调整大小
/******************************************************************** * qt 窗口控件自动调整大小 * * 在写gui的时候,希 ...
- 科技发烧友之单反佳能700d中高端
http://detail.zol.com.cn/series/15/15795_1.html 前三 佳能 尼康 索尼 佳能5d 1.6w 佳能70d 5k 佳能6d 9k 佳能d7100 5k 尼康 ...
- iOS 开发系列:CoreData Object 变成 Fault 的一种方式
@quote: 近来一直与 CoreData 打交道.这是一个架构庞大.学习曲线比較陡峭的 iOS 组件,每次遇到问题都会对其有新的认识. 这次就仅仅讲一点,关于错误认知 Object(NSManag ...