物联网 基于netty构建mqtt协议规范(轻量级二进制协议)
简述
在物联网、游戏服务器、RPC 等场景中,需要高效的网络通信。 二进制协议相比 JSON/XML 等文本协议,具有更小的体积、更快的解析速度、更低的内存占用等优势。 设计一个简单的二进制协议,并基于 Netty 实现完整的编解码器,深入理解二进制协议的开发流程
源码(netty-sample-03-Binary)
https://gitee.com/kcnf-iot/iot-sample/tree/master/netty/netty-sample-03
协议设计
类 MQTT 风格 的轻量级二进制协议
| 字段 | 字节数 | 描述 |
|---|---|---|
| 魔数 (Magic) | 1 | 固定为 0xAA,用于快速校验和过滤非法连接 |
| 消息类型 (Type) | 1 | 1=请求,2=响应,3=心跳 |
| 消息ID (MsgId) | 4 | 大端序整数,用于请求-响应关联 |
| 数据长度 (Length) | 2 | 无符号短整型(最大 65535),表示后面数据字段的字节数 |
| 数据 (Data) | Length | 二进制数据(例如 UTF-8 字符串或其他内容) |
协议总长度:1+1+4+2+Length = 8+Length 字节
优点
魔数帮助快速判断连接是否为合法客户端
长度字段为 2 字节,可表示最大 64KB 的消息体,适合小型物联网设备
消息 ID 使我们可以实现请求-响应的异步模型(如 RPC)
为什么二进制协议更轻量
| 特性 | 文本协议 (JSON) | 二进制协议 |
|---|---|---|
| 数字编码 | "123" 占用3字节 | 0x7B 占用1字节 |
| 布尔值 | "true" 占用4字节 | 1位或1字节 |
| 字段名 | 每次重复发送 | 靠偏移量隐式约定 |
| 解析开销 | 字符串扫描、递归下降 | 按位移位、直接取值 |
示例:{"id":1} | 8字节 | 若协议仅发送 id 数值,只需 4 字节(二进制 int) |
server代码
package com.jysemel.iot.pojo;
import com.jysemel.iot.pojo.coder.BinaryMessageDecoder;
import com.jysemel.iot.pojo.coder.BinaryMessageEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class BinaryProtocolServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
// 添加二进制解码器和编码器
p.addLast(new BinaryMessageDecoder());
p.addLast(new BinaryMessageEncoder());
p.addLast(new ServerBusinessHandler());
}
});
ChannelFuture future = bootstrap.bind(8088).sync();
System.out.println("二进制协议服务器启动,端口 8088");
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
client代码
package com.jysemel.iot.pojo;
import com.jysemel.iot.pojo.coder.BinaryMessageDecoder;
import com.jysemel.iot.pojo.coder.BinaryMessageEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class BinaryProtocolClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new BinaryMessageDecoder());
p.addLast(new BinaryMessageEncoder());
p.addLast(new ClientBusinessHandler());
}
});
ChannelFuture future = bootstrap.connect("127.0.0.1", 8088).sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
验证结果


