2.Netty的粘包、拆包(一)

时间:2024-01-21 22:17:05

Netty粘包、拆包

1.什么是拆包、粘包

(1)拆包、粘包介绍

TCP是个“流”协议,所谓流,就是没有界限的一串数据。大家可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

(2)图解

(3)代码模拟

  1. 服务端Server

    package com.xm.netty.demo02;
    
    import java.net.InetSocketAddress;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    public class Server {
    
     private final int port;
    
     public Server(int port) {
         this.port = port;
     }
    
    
    
     public static void main(String[] args) {
    
         int port = 8989;
         try {
             new Server(port).start();
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
    
     }
    
    
    
     private void start() throws InterruptedException {
         EventLoopGroup g1 = new NioEventLoopGroup();
         EventLoopGroup g2 = new NioEventLoopGroup();
         try {
             ServerBootstrap bootstrap = new ServerBootstrap();
              bootstrap
                     .group(g1,g2)
                     .channel(NioServerSocketChannel.class)
                     .localAddress(new InetSocketAddress( port))
                     .childHandler(new ChannelInitializer() {
                         @Override
                         protected void initChannel(Channel ch) throws Exception {
                             ch.pipeline().addLast(new ServerHandler());
                         }
                     });
              ChannelFuture future = bootstrap.bind().sync();
              future.channel().closeFuture().sync();
         } finally {
             g1.shutdownGracefully().sync();
             g2.shutdownGracefully().sync();
         }
     }
    
    }
    
  2. 服务端ServerHandler

    package com.xm.netty.demo02;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.util.CharsetUtil;
    
    public class ServerHandler extends ChannelHandlerAdapter {
    
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
         ByteBuf in = (ByteBuf) msg;
         String str = in.toString(CharsetUtil.UTF_8);
         System.out.println("Server:"+str);
         str = "服务器返回--->"+ str;
         ctx.writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
     }
    
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
         cause.printStackTrace();
         ctx.close();
     }
    
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
         System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())+"一个客户端连接!");
     }
    
    
    }
    
  3. 客户端Client

    package com.xm.netty.demo02;
    
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    public class Client {
    
     private final int port;
     private final String host;
    
    
    
     public Client(int port, String host) {
         this.port = port;
         this.host = host;
     }
    
     public static void main(String[] args) {
         String host = "127.0.0.1";
         int port = 8989;
         try {
             new Client(port, host).start();
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }
    
     private void start() throws InterruptedException {
    
         EventLoopGroup group = new NioEventLoopGroup();
         try {
             Bootstrap bootstrap = new Bootstrap();
             bootstrap
                     .group(group)
                     .channel(NioSocketChannel.class)
                     .remoteAddress(host, port)
                     .handler(new ChannelInitializer<SocketChannel>() {
    
                         @Override
                         protected void initChannel(SocketChannel ch) throws Exception {
                             ch.pipeline().addLast(new ClientHandler());
                         }
    
                     });
    
             ChannelFuture future = bootstrap.connect().sync();
    
             for(int i=10;i<20;i++) {
                 String str = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()) + "---- " +i+"<<<";
                 future.channel().writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
             }
    
    
    
    
             future.channel().closeFuture().sync();
         } finally {
             group.shutdownGracefully().sync();
         }
    
     }
    
    }
    
  4. 客户端ClientHandler

    package com.xm.netty.demo02;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.util.CharsetUtil;
    import io.netty.util.ReferenceCountUtil;
    
    public class ClientHandler extends ChannelHandlerAdapter {
    
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
    
         try {
    
             ByteBuf in = (ByteBuf) msg;
             String str = in.toString(CharsetUtil.UTF_8);
             System.out.println("Client:"+str);
    
         } finally {
             ReferenceCountUtil.release(msg);
         }
     }
    
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
         cause.printStackTrace();
         ctx.close();
     }
    
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
         System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())+"  已连接上服务器!");
     }
    
    
    }
    
  5. 添加依赖

  6. 预期结果

    1)服务器

    2018-10-11T18:37:19.857一个客户端连接!

    Server:2018-10-11T18:37:19.855---- 10<<<

    Server:2018-10-11T18:37:20.377---- 11<<<

    Server:2018-10-11T18:37:20.877---- 12<<<

    Server:2018-10-11T18:37:21.378---- 13<<<

    Server:2018-10-11T18:37:21.879---- 14<<<

    Server:2018-10-11T18:37:22.379---- 15<<<

    Server:2018-10-11T18:37:22.879---- 16<<<

    Server:2018-10-11T18:37:23.38---- 17<<<

    Server:2018-10-11T18:37:23.881---- 18<<<

    Server:2018-10-11T18:37:24.382---- 19<<<

    (2)客户端

    2018-10-11T18:37:19.855 已连接上服务器!

    Client:服务器返回--->2018-10-11T18:37:19.855---- 10<<<

    Client:服务器返回--->2018-10-11T18:37:20.377---- 11<<<

    Client:服务器返回--->2018-10-11T18:37:20.877---- 12<<<

    Client:服务器返回--->2018-10-11T18:37:21.378---- 13<<<

    Client:服务器返回--->2018-10-11T18:37:21.879---- 14<<<

    Client:服务器返回--->2018-10-11T18:37:22.379---- 15<<<

    Client:服务器返回--->2018-10-11T18:37:22.879---- 16<<<

    Client:服务器返回--->2018-10-11T18:37:23.38---- 17<<<

    Client:服务器返回--->2018-10-11T18:37:23.881---- 18<<<

    Client:服务器返回--->2018-10-11T18:37:24.382---- 19<<<

  7. 实际结果

    (1)服务器

    2018-10-11T18:35:40.988一个客户端连接!
    Server:2018-10-11T18:35:40.986---- 10<<<2018-10-11T18:35:41.01---- 11<<<2018-10-11T18:35:41.01---- 12<<<2018-10-11T18:35:41.01---- 13<<<2018-10-11T18:35:41.01---- 14<<<2018-10-11T18:35:41.01---- 15<<<2018-10-11T18:35:41.01---- 16<<<2018-10-11T18:35:41.01---- 17<<<2018-10-11T18:35:41.01---- 18<<<2018-10-11T18:35:41.01---- 19<<<

    (2)客户端

    2018-10-11T18:35:40.986 已连接上服务器!
    Client:服务器返回--->2018-10-11T18:35:40.986---- 10<<<2018-10-11T18:35:41.01---- 11<<<2018-10-11T18:35:41.01---- 12<<<2018-10-11T18:35:41.01---- 13<<<2018-10-11T18:35:41.01---- 14<<<2018-10-11T18:35:41.01---- 15<<<2018-10-11T18:35:41.01---- 16<<<2018-10-11T18:35:41.01---- 17<<<2018-10-11T18:35:41.01---- 18<<<2018-10-11T18:35:41.01---- 19<<<