Netty 框架学习(二):DelimiterBasedFrameDecoder和FixedLengthFrameDecoder
文章目錄
- 一、DelimiterBasedFrameDecoder
- 服務端
- 1、EchoServer
- 2、EchoServerChannelHandler
- 3、EchoServerHandler
- 客戶端
- 1、EchoClient
- 2、EchoClientChannelHandler
- 3、EchoClientHandler
- 二、FixedLengthFrameDecoder
TCP以流的方式進行數據傳輸,上層應用協議為了對消息進行區分,一般采用如下4種方式:
1.消息長度固定,累計讀取到消息長度總和為定長Len的報文之后即認為是讀取到了一個完整的消息。計數器歸位,重新讀取。
2. 將回車換行符作為消息結束符。
3. 將特殊的分隔符作為消息分隔符,回車換行符是他的一種。
4. 通過在消息頭定義長度字段來標識消息總長度。
LineBasedframeDecoder屬于第二種,今天我們要說的DelimiterBasedFrameDecoder和FixedLengthFrameDecoder屬于第三種和第一種。DelimiterBasedFrameDecoder用來解決以特殊符號作為消息結束符的粘包問題,FixedLengthFrameDecoder用來解決定長消息的粘包問題。
一、DelimiterBasedFrameDecoder
服務端
1、EchoServer
/*** @author shuliangzhao* @Title: EchoServer* @ProjectName design-parent* @Description: TODO* @date 2019/8/21 20:53*/ public class EchoServer {public void start(int port) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap().group(bossGroup,workGroup).channel(NioServerSocketChannel.class).childHandler(new EchoServerChannelHandler());try {ChannelFuture future = serverBootstrap.bind(port).sync();future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}public static void main(String[] args) {new EchoServer().start(8080);} }2、EchoServerChannelHandler
/*** @author shuliangzhao* @Title: EchoServerChannelHandler* @ProjectName design-parent* @Description: TODO* @date 2019/8/21 20:59*/ public class EchoServerChannelHandler extends ChannelInitializer<SocketChannel> {protected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline = socketChannel.pipeline();ByteBuf byteBuf = Unpooled.copiedBuffer("\t".getBytes());pipeline.addLast(new DelimiterBasedFrameDecoder(1024,byteBuf));pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());pipeline.addLast(new EchoServerHandler());} }3、EchoServerHandler
public class EchoServerHandler extends ChannelInboundHandlerAdapter {private int counter;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String body = (String) msg;System.out.println("server reciver oder:" + body + ";this counter is:" + ++counter);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {super.exceptionCaught(ctx, cause);} }客戶端
1、EchoClient
public class EchoClient {public void start(String address,int port) {EventLoopGroup group = new NioEventLoopGroup();Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new EchoClientChannelHandler());try {ChannelFuture future = bootstrap.connect(address,port).sync();future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();}finally {group.shutdownGracefully();}}public static void main(String[] args) {new EchoClient().start("127.0.0.1",8080);} }2、EchoClientChannelHandler
public class EchoClientChannelHandler extends ChannelInitializer<SocketChannel> {protected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline = socketChannel.pipeline();/** 這個地方的 必須和服務端對應上。否則無法正常解碼和編碼*/ByteBuf delimiter = Unpooled.copiedBuffer("\t".getBytes());pipeline.addLast(new DelimiterBasedFrameDecoder(1024,delimiter));pipeline.addLast( new StringDecoder());pipeline.addLast( new StringEncoder());// 客戶端的邏輯pipeline.addLast( new EchoClientHandler());} }3、EchoClientHandler
public class EchoClientHandler extends ChannelInboundHandlerAdapter {private byte[] req;private int counter;public EchoClientHandler() {req = ("There are moments in life when you miss\t" +"someone so much that you just want to pick\t" +"them from your dreams and hug them for real!\t" +"Dream what you want to dream;go where you want\t" +"to go be what you want to be,because you have only\t" +"one life and one chance to do all the things you want to do\t").getBytes();}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ByteBuf message = Unpooled.buffer(req.length);message.writeBytes(req);ctx.writeAndFlush(message);}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String body = (String) msg;System.out.println("client reciver is :" + body + "this is counter:" + ++counter);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();} }運行結果:
這里我們添加DelimiterBasedFrameDecoder解碼器并且手動指定消息分隔符為:”\t”。我們可以看一下DelimiterBasedFrameDecoder的構造方法:
maxFrameLength:解碼的幀的最大長度
stripDelimiter:解碼時是否去掉分隔符
failFast:為true,當frame長度超過maxFrameLength時立即報TooLongFrameException異常,為false,讀取完整個幀再報異常
delimiter:分隔符
二、FixedLengthFrameDecoder
FixedLengthFrameDecoder是固定長度解碼器,它能夠按照指定的長度對消息進行自動解碼。
用法如下:
pipeline.addLast(new FixedLengthFrameDecoder(23));//參數為一次接受的數據長度。
總結
以上是生活随笔為你收集整理的Netty 框架学习(二):DelimiterBasedFrameDecoder和FixedLengthFrameDecoder的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Netty 框架学习(二):Netty粘
- 下一篇: JWT(JSON Web Token)简