Netty TCP粘包/拆包问题解决之道

一TCP 粘包/拆包

 Tcp是个”流“协议,所谓流,就是没有界限的一串数据。

 一个完整的包,可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题

 

二、粘包问题的解决策略

  (1)消息定长。报文大小固定长度,不够空格补全。发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。  

  (2)包尾添加特殊分隔符,例如每条报文结束都添加回车换行符(例如FTP协议)或者指定特殊字符作为报文分隔符,接收方通过特殊分隔符切分报文区分。

  (3)将消息分为消息头和消息体,消息头中包含表示信息的总长度(或者消息体长度)的字段

  (4)其他应用层协议

 

三 Netty提供的半包解码器解决TCP粘包/拆包问题

1 利用LineBaseFrameDecoder解决TCP粘包问题

LineBaseFrameDecoder工作原理是它依次遍历ByteBuf中的可读字节,判断看是否有"\n"或者"\r\n",如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。它是以换行符为结束标识的解码器,支持携带结束符,或者不携带结束符两种解码方式,同时支持配置单行的最大长度。如果连续读取到最大长度后仍然没有发现换行符,就抛出异常,同时忽略掉之前读到的异常码流。

2 StringDecoder

StringDecoder的功能非常简单,就是将接收到的对象转换成字符串,然后继续调用后面的handler.

LineBaseFrameDecoder+StringDecoder组合是按行切换的文本解码器,它被设计用来支持TCP的粘包和拆包。

 

四 实列

1 服务端

public static  void main(String[] arg) throws  InterruptedException
{
    //定义两个事件组
    //接收连接但是不对连接做任何处理会把事情交给workerGroup去做
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
  try {


      //启动服务
      ServerBootstrap serverBootStrap = new ServerBootstrap();
      serverBootStrap.group(bossGroup, workerGroup)
              .channel(NioServerSocketChannel.class)
              .option(ChannelOption.SO_BACKLOG, 1024)
              .childHandler(new ChildChannelHandler());
      //绑定端口
      ChannelFuture f = serverBootStrap.bind(8080).sync();
      //等待服务端 监听端口关闭
      f.channel().closeFuture().sync();
  }catch (Exception ex)
  {


  }
  finally {
      //优雅的关闭Netty
      bossGroup.shutdownGracefully();
      workerGroup.shutdownGracefully();
  }
}
private static class ChildChannelHandler extends ChannelInitializer<SocketChannel>
{


    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        // LineBasedFrameDecoder 添加行解析器,添加stringDecoder
        //StringDecoder作用就是将接收到的消息转为字符串
        socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
        socketChannel.pipeline().addLast(new StringDecoder());

        socketChannel.pipeline().addLast("TestHttpServerHandler",new TestHttpServerHandler());
    }
}

2 客户端

public static  void main(String[] arg)
{
    EventLoopGroup group = new NioEventLoopGroup();
    try{

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY,true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        // LineBasedFrameDecoder 添加行解析器,添加stringDecoder
                        //StringDecoder作用就是将接收到的消息转为字符串
                        pipeline.addLast(new LineBasedFrameDecoder(1024));
                        pipeline.addLast(new StringDecoder());
                        pipeline.addLast(new LoggingHandler(LogLevel.INFO))
                                .addLast(new TimeClientHandler());

                    }
                });

        //start the client
        ChannelFuture future = bootstrap.connect("127.0.0.1", 8080).sync();
        //wait until the connection is closed
        future.channel().closeFuture().sync();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        //shut down the event loop to terminate all threads
        group.shutdownGracefully();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值