Netty入门(十)解码分隔符和基于长度的协议
2024-08-24 16:30:45
我们需要区分不同帧的首尾,通常需要在结尾设定特定分隔符或者在首部添加长度字段,分别称为分隔符协议和基于长度的协议,本节讲解 Netty 如何解码这些协议。
一、分隔符协议
Netty 附带的解码器可以很容易的提取一些序列分隔:
下面显示了使用 “\r\n”分隔符的处理:
下面为 LineBaseFrameDecoder 的简单实现:
public class CmdHandlerInitializer extends ChannelInitializer<Channel> { @Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加解码器,
pipeline.addLast(new CmdDecoder(65 * 1024));
pipeline.addLast(new CmdHandler());
} public static final class Cmd {
private final ByteBuf name; // 名字
private final ByteBuf args; // 参数 public Cmd(ByteBuf name, ByteBuf args) {
this.name = name;
this.args = args;
} public ByteBuf name() {
return name;
} public ByteBuf args() {
return args;
}
} /**
* 根据分隔符将消息解码成Cmd对象传给下一个处理器
*/
public static final class CmdDecoder extends LineBasedFrameDecoder { public CmdDecoder(int maxLength) {
super(maxLength);
} @Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
// 通过结束分隔符从 ByteBuf 提取帧
ByteBuf frame = (ByteBuf)super.decode(ctx, buffer);
if(frame == null)
return null;
int index = frame.indexOf(frame.readerIndex(), frame.writerIndex(), (byte)' ');
// 提取 Cmd 对象
return new Cmd(frame.slice(frame.readerIndex(), index),
frame.slice(index+1, frame.writerIndex()));
}
} public static final class CmdHandler extends SimpleChannelInboundHandler<Cmd> { @Override
protected void channelRead0(ChannelHandlerContext ctx, Cmd msg) throws Exception {
// 处理 Cmd 信息
} }
}
上面的例子主要实现了利用换行符‘\n’分隔帧,然后将每行数据解码成一个 Cmd 实例。
二、基于长度的协议
基于长度的协议在帧头定义了一个帧编码的长度,而不是在结束位置用一个特殊的分隔符来标记。Netty 提供了两种编码器,用于处理这种类型的协议,如下:
FixedLengthFrameDecoder 的操作是提取固定长度每帧 8 字节,如下图所示:
但大部分时候,我们会把帧的大小编码在头部,这种情况可以使用 LengthFieldBaseFrameDecoder,它会提取帧的长度并根据长度读取帧的数据部分,如下:
下面是 LengthFieldBaseFrameDecoder 的一个简单应用:
/**
* 基于长度的协议
* LengthFieldBasedFrameDecoder
*/
public class LineBasedHandlerInitializer extends ChannelInitializer<Channel> { @Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 用于提取基于帧编码长度8个字节的帧
pipeline.addLast(new LengthFieldBasedFrameDecoder(65*1024, 0, 8));
pipeline.addLast(new FrameHandler());
} public static final class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
// TODO 数据处理
} } }
上面的例子主要实现了提取帧首部 8 字节的长度,然后提取数据部分进行处理。
最新文章
- 求两个数字的最大公约数-Python实现,三种方法效率比较,包含质数打印质数的方法
- jQuery初级篇(一)
- Java Synchronized Blocks
- github添加ssh key报错Key is invalid. Ensure you&#39;ve copied the file correctly
- iOS - OC/Swift:验证手机号/固话用正则表达式
- 服务器资源共享--IIS站点/虚拟目录中访问共享目录(UNC)
- 使用ListView时遇到的问题
- virtualBox使用nat模式下ssh连接
- 报错:No identifier specified for entity: main.java.com.sy.entity.User的解决办法
- jQuery 选择器 prop() 和attr()
- yum出现Loaded plugins: fastestmirror, security Loading mirror speeds from cached hostfile解决方法
- 值得收藏!!javascript数组中多条对象去重方式,很实用!!!
- Ehcache入门经典:第一篇
- Jenkins之使用Pyinstaller构建Python应用程序
- python 搭建一个简单的 搜索引擎
- Docker 入门指南——部署常用服务示例
- Django CBV与FBV
- KVM虚拟化之windows虚拟机性能调整
- 云计算之路-阿里云上:踩着RDS的2个坑
- nodejs入门-做一个代理服务器
热门文章
- StreamReader 的ReadLine,Read,ReadToEnd方法
- EF 求和 GroupBy多个字段
- 转载-asp.net id 和name的区别
- Java - ";JUC"; ReentrantLock释放锁
- AutoFac实现WebAPI依赖注入(EF以及Mysql)
- openstack-on-centos7之环境准备
- vue 自定义组件的自定义属性
- OSGI企业应用开发(十二)OSGI Web应用开发(一)
- 页面可见性判断:document.hidden与visibilitychange事件
- GridLayout和GridView的区别