Netty解决粘包和拆包问题

在Netty中解决拆包和粘包的问题,我们只需要将解码器添加到ChannelPipeline中就可以了。

LineBasedFrameDecoder的工作原理就是它依次遍历ByteBuf中的可读字节,如果有\n和\r\n,就以此为结束位置,它是以换行符为结束标志的解码器。如果读取到行的最大长度还没有发现换行,就会抛出异常,同时忽略掉之前读到的异常码流。

StringDecoder就是讲收到的对象转换成字符串。

上面这两种解码器结合起来其实就是换行切换的文本解码器。

后续还会涉及到分隔符的解码器和定长解码器

import io.netty.bootstrap.ServerBootstrap;
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.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
 * @FileName TimeServer.java
 * @Description:
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
public class TimeServer {
 public void bind(int port) throws Exception {
  // 配置服务端的NIO线程组
  EventLoopGroup bossGroup = new NioEventLoopGroup();
  EventLoopGroup workerGroup = new NioEventLoopGroup();
  try {
   /**
    * 创建ServerBootstrap,它是Netty用于启动NIO服务端的辅助启动类
    */
   ServerBootstrap b = new ServerBootstrap();
   /**
    * 创建管道NioServerSocketChannel,也就是NIO中的ServerSocketChannel,然后设置TCP的参数
    * ,设置为1024,最后
    * 创建ChildChannelHandler,也就是Reactor模式中的handler类,用于处理网络IO时间
    * ,比如对消息的编解码。
    */
   b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
     .childHandler(new ChildChannelHandler());
   /**
    * 绑定端口,同步等待成功
    * 绑定完成之后会返回一个ChannelFuture,这里类似于JDK的java.util.concurrent.Future。
    * 用于异步操作的通知回调
    */
   ChannelFuture f = b.bind(port).sync();
   // 等待服务端监听端口关闭
   f.channel().closeFuture().sync();
  } finally {
   // 优雅退出,释放线程池资源
   bossGroup.shutdownGracefully();
   workerGroup.shutdownGracefully();
  }
 }
 
 
 private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
  @Override
  protected void initChannel(SocketChannel arg0) throws Exception {
   //添加解码器
   arg0.pipeline().addLast(new LineBasedFrameDecoder(1024));
   arg0.pipeline().addLast(new StringDecoder());
   arg0.pipeline().addLast(new TimeServerHandler());
  }
 }
 /**
  * @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 TimeServer().bind(port);
 }
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/**
 * @FileName TimeServerHandler.java
 * @Description:用于对网络事件读写操作
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
public class TimeServerHandler extends ChannelHandlerAdapter {
 private int counter;
 
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  //添加解码器后不需要考虑处理读半包的问题,也不需要对客户端请求的消息msg进行编码
  String body = (String) msg;
  System.out.println("The time server receive order : " + body +";记录数 -----: " + ++counter);
  String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString()
    : "BAD ORDER";
  currentTime = currentTime + System.getProperty("line.separator");
  ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
  ctx.writeAndFlush(resp);
 }
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  ctx.close();
 }
}
import io.netty.bootstrap.Bootstrap;
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.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
 * @FileName TimeClient.java
 * @Description: 
 *
 * @Date 2016年3月2日 
 * @author Administroter
 * @version 1.0
 * 
 */
public class TimeClient {
 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>() {
    public void initChannel(SocketChannel ch)
     throws Exception {
     //添加解码器
     ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
     ch.pipeline().addLast(new StringDecoder());
        ch.pipeline().addLast(new TimeClientHandler());
    }
       });
      // 发起异步连接操作
      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 TimeClient().connect(port, "127.0.0.1");
     }
}
import java.util.logging.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/**
 * @FileName TimeClientHandler.java
 * @Description:
 *
 * @Date 2016年3月2日
 * @author Administroter
 * @version 1.0
 * 
 */
public class TimeClientHandler extends ChannelHandlerAdapter {
 private static final Logger logger = Logger.getLogger(TimeClientHandler.class.getName());
 private int counter;
 private byte[] request;
 /**
  * Creates a client-side handler.
  */
 public TimeClientHandler() {
  request = ("QUERY TIME ORDER"+System.getProperty("line.separator")).getBytes();
 }
 /**
  * TCP链路建立成功后,调用这个方法发送查询指令给服务器
  */
 @Override
 public void channelActive(ChannelHandlerContext ctx) {
  ByteBuf message = null;
  for (int i = 0; i < 100; i++) {
   message = Unpooled.buffer(request.length);
   message.writeBytes(request);
   ctx.writeAndFlush(message);
  }
 }
 /**
  * 服务器你响应结果后调用这个方法,获取服务器响应的结果
  */
 @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 exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  // 释放资源
  logger.warning("Unexpected exception from downstream : " + cause.getMessage());
  ctx.close();
 }
}

你可能感兴趣的:(粘包,拆包,Netty拆包和粘包)