DelimiterBasedFrameDecoder案例

DelimiterBasedFrameDecoder案例教程

上一章,我们了解了 DelimiterBasedFrameDecoder 理论知识,它在 Netty 中是一个特殊字符码解码器,有着很重要的作用。它会找接收到的消息里面是否有自定义的特殊字符 。如果有就认为这个标识之前的数据就是一段数据。

案例

我们新建一个 Maven 项目,然后在根 pom 文件中引入 Netty 相关 jar 包。代码如下:

<dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.20.Final</version> </dependency> </dependencies>

Server端

DelimiterBasedFrameServer

package net.haicoder.delimiterBasedFrameDecoder; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; public class DelimiterBasedFrameServer { public void bind(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); ByteBuf delimiter1 = Unpooled.copiedBuffer("*_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter,delimiter1)); ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new DelimiterBasedFrameServerHandler()); } }); ChannelFuture future = b.bind(port).sync(); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; new DelimiterBasedFrameServer().bind(port); } }

DelimiterBasedFrameServerHandler

package net.haicoder.delimiterBasedFrameDecoder; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class DelimiterBasedFrameServerHandler extends ChannelInboundHandlerAdapter { int counter = 0; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String body = (String) msg; System.out.println("This is " + ++counter + " times receive client : [ " + body + " ]"); //客户端也需要根据这个特殊字符进行解码,所以我们在返回客户端之前也加了该特殊字符 body += "$_"; ByteBuf echo = Unpooled.copiedBuffer(body.getBytes()); ctx.writeAndFlush(echo); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.close(); } }

客户端

DelimiterBasedFrameClient

package net.haicoder.delimiterBasedFrameDecoder; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; public class DelimiterBasedFrameClient { public void connect(int port, String host) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter)); ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new DelimiterBasedFrameClientHandler()); } }); ChannelFuture f = b.connect(host, port).sync(); f.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; new DelimiterBasedFrameClient().connect(port, "127.0.0.1"); } }

DelimiterBasedFrameClientHandler

package net.haicoder.delimiterBasedFrameDecoder; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class DelimiterBasedFrameClientHandler extends ChannelInboundHandlerAdapter { private int counter; static final String ECHO_REQ = "你好,嗨客网,欢迎来到 Netty 世界。$_,哈哈,你可以成功的。"; @Override public void channelActive(ChannelHandlerContext ctx) { for (int i = 0; i < 3; i++) { ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes())); } } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("This is " + ++counter + " times receive server : [" + msg + " ]"); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.close(); } }

运行结果如下:

服务端

06 分割符解码器服务端运行结果.png

客户端

07 客户端分割解码器运行结果.png

DelimiterBasedFrameDecoder案例总结

DelimiterBasedFrameDecoder 是特殊字符解码器,它可以识别自定义的特殊字符,然后将特殊字符之间的数据进行截取。