概述
在李林锋的Netty系列之Netty编解码框架阐明中先容了各类解码器,也推荐组合
LengthFieldBasedFrameDecoder ByteToMessageDecoder
这两个解码器来处理惩罚业务动静。可是有时候为了机动性,会直接选择担任
ByteToMessageDecoder
来处理惩罚业务动静,可是直接担任ByteToMessageDecoder,则需要本身处理惩罚半包问题。在李林锋的【netty权威指南】中,并没有描写如何自界说解码器来处理惩罚半包动静。下文会先容这方面的常识。
在阅读本文内容之前,劳务派遣管理系统,你至少需要相识以下两个常识点
1、 netty的ByteBuf类的根基api用法
2、什么是TCP半包
固然JAVA NIO中也有个ByteBuffer类,可是在Netty措施中,根基都是直接用Netty的ByteBuf类,它包装了更多好用的接口,低落了利用缓冲区类的难度。
之前本人写过几篇关于处理惩罚半包动静的文章,读者也可以参看一下
自界说动静协议
今朝自界说的动静协议用的最多的是在动静中头四个字节生存动静的长度,名目或许如下
无论每次请求的业务数据多大,都是利用上面的动静名目来暗示的。
留意
在实际的项目中,动静名目大概会增加一些符号,譬喻,开始标志,竣事符号,动静序列号,动静的协议范例(json可能二进制等),这里为了描写的利便,就不讲附加的这些动静符号了。
自界说解码器处理惩罚半包数据
如上描写,直接担任ByteToMessageDecoder类,同时包围其decode要领,完整实现代码如下
处事端代码
package nettyinaction.encode.lengthfield.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; public class SocketServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup parentGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(parentGroup, childGroup) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new SocketServerInitializer()); ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); channelFuture.channel().closeFuture().sync(); } finally { parentGroup.shutdownGracefully(); childGroup.shutdownGracefully(); } } } package nettyinaction.encode.lengthfield.server; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; public class SocketServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new SelfDefineEncodeHandler()); pipeline.addLast(new BusinessServerHandler()); } } package nettyinaction.encode.lengthfield.server; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import java.util.List; public class SelfDefineEncodeHandler extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception { if (bufferIn.readableBytes() < 4) { return; } int beginIndex = bufferIn.readerIndex(); int length = bufferIn.readInt(); if ((bufferIn.readableBytes()+1) < length) { bufferIn.readerIndex(beginIndex); return; } bufferIn.readerIndex(beginIndex + 4 + length); ByteBuf otherByteBufRef = bufferIn.slice(beginIndex, 4 + length); otherByteBufRef.retain(); out.add(otherByteBufRef); } } package nettyinaction.encode.lengthfield.server; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class BusinessServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf)msg; int length = buf.readInt(); assert length == (8); byte[] head = new byte[4]; buf.readBytes(head); String headString = new String(head); assert "head".equals(headString); byte[] body = new byte[4]; buf.readBytes(body); String bodyString = new String(body); assert "body".equals(bodyString); } }