Netty解码器

DelimiterBasedFrameDecoder解码器主要针对一些特殊带分割符的消息进行自动解码

下面就是对以“$_”结尾的消息进行自动解码的过程,先创建一个分隔符缓冲对象,然后在ChannelPipeline中添加解码器,并设置它的以特殊字符结尾前这一行的最大消息长度,如果在最大长度之前还没有找到我们定义的特殊分隔符。就会抛出TooLongFrameException异常,防止由于异常码流缺失分隔符导致的内存溢出。

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;
/**
 * @FileName EchoClient.java
 * @Description:DelimiterBasedFrameDecoder解码器测试客户端
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
public class EchoClient {
 public void connect(int port, String host) throws Exception {
  // 配置客户端NIO线程组
  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
      public 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 EchoClientHandler());
      }
     });
   // 发起异步连接操作
   ChannelFuture f = b.connect(host, port).sync();
   // 当代客户端链路关闭
   f.channel().closeFuture().sync();
  } finally {
   // 优雅退出,释放NIO线程组
   group.shutdownGracefully();
  }
 }
 /**
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  int port = 8080;
  if (args != null && args.length > 0) {
   try {
    port = Integer.valueOf(args[0]);
   } catch (NumberFormatException e) {
    // 采用默认值
   }
  }
  new EchoClient().connect(port, "127.0.0.1");
 }
}
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/**
 * @FileName EchoClient.java
 * @Description:DelimiterBasedFrameDecoder解码器测试客户端
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
public class EchoClientHandler extends ChannelHandlerAdapter {
 private int counter;
 /**
  * Creates a client-side handler.
  */
 public EchoClientHandler() {
 }
 @Override
 public void channelActive(ChannelHandlerContext ctx) {
  //建立连接后循环向服务器请求,发送以"$_"结尾的字符
  for (int i = 0; i < 10; i++) {
   ctx.writeAndFlush(Unpooled.copiedBuffer("发送服务器的请求参数.$_".getBytes()));
  }
 }
 /**
  * 服务器你响应结果后调用这个方法,获取服务器响应的结果
  */
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  //读取服务器端响应的数据
  String body = (String)msg;
  System.out.println("服务器器响应结果 : " + body + "; the counter is : " + ++counter);
 }
 @Override
 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  ctx.flush();
 }
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  cause.printStackTrace();
  ctx.close();
 }
}
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;
/**
 * @FileName EchoClient.java
 * @Description:DelimiterBasedFrameDecoder解码器测试服务器端
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
public class EchoServer {
 public void bind(int port) throws Exception {
  // 配置服务端的NIO线程组
  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
      public void initChannel(SocketChannel ch) throws Exception {
       //分隔符缓冲对象
       ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
       //添加解码器DelimiterBasedFrameDecoder,并设置消息最大长度和消息缓冲对象,即消息是以"$_"作为分隔符
       ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
       ch.pipeline().addLast(new StringDecoder());
       ch.pipeline().addLast(new EchoServerHandler());
      }
     });
   // 绑定端口,同步等待成功
   ChannelFuture f = b.bind(port).sync();
   // 等待服务端监听端口关闭
   f.channel().closeFuture().sync();
  } finally {
   // 优雅退出,释放线程池资源
   bossGroup.shutdownGracefully();
   workerGroup.shutdownGracefully();
  }
 }
 public static void main(String[] args) throws Exception {
  int port = 8080;
  if (args != null && args.length > 0) {
   try {
    port = Integer.valueOf(args[0]);
   } catch (NumberFormatException e) {
    // 采用默认值
   }
  }
  new EchoServer().bind(port);
 }
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/**
 * @FileName EchoClient.java
 * @Description:DelimiterBasedFrameDecoder解码器测试服务器端
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
@Sharable
public class EchoServerHandler extends ChannelHandlerAdapter {
 int counter = 0;
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  //在前面我们添加了StringDecoder解码器,所有这个地方获取到的客户端信息msg就是解码后的消息
  String body = (String)msg;
  System.out.println("This is" + ++counter + "times reveive client: [" + body + "]");
  //客户端请求参数拼接'$_'
  body += "----数据来自服务器$_";
  //创建ByteBuf,将原始数据返回给客户端
  ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
  ctx.writeAndFlush(echo);
 }
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  cause.printStackTrace();
  ctx.close();// 发生异常,关闭链路
 }
}

FixedLengthFrameDecoder通过固定长度来对消息进行自动解码,我们改下ChannelPipeline添加的编码器,将前面的DelimiterBasedFrameDecoder更换成FixedLengthFrameDecoder并设置它的长度限制为20,,这个时候,我们再通过IO的处理类将客户端请求过来的信息打印出来,如果客户端发送过来的请求消息大于20,,,则消息会被截取,只保留前20的消息

 public void initChannel(SocketChannel ch) throws Exception {
       //添加FixedLengthFrameDecoder固定长度解码器,并设置长度为20
       ch.pipeline().addLast(new FixedLengthFrameDecoder(20));
       ch.pipeline().addLast(new StringDecoder());
       ch.pipeline().addLast(new FixedLengthServerHandler());
      }

你可能感兴趣的:(netty,Netty解码器)