您当前的位置: 首页 >  .net

墨家巨子@俏如来

暂无认证

  • 0浏览

    0关注

    188博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

十二.Netty入门到超神系列-TCP粘包拆包处理

墨家巨子@俏如来 发布时间:2021-12-07 16:16:42 ,浏览量:0

前言

TCP是面向连接的,服务端和客户端通过socket进行数据传输,发送端为了更有效的发送数据,通常会使用Nagle算法把多个数据块合并成一个大的数据块,这样做虽然提高了效率,但是接收端就很难识别完整的数据包了(TCP无消息保护边界),可能会出现粘包拆包的问题。

粘包拆包理解

下面我用一个图来带大家理解什么是粘包和拆包 在这里插入图片描述 解释一下

  • 第一次传输没有问题,数据1和数据2没有粘合,也没有拆分
  • 第二次传输,数据1和数据2粘在一起传输了,出现了粘包
  • 第三次传输,数据2被分为了2部分,数据2_1 第一份和数据1粘在一起,数据2_2第二份单独传输,这里即出现了拆包也出现了粘包
粘包拆包代码演示

这里写一个简单案例来演示粘包拆包,客户端发送10个数据包,观察服务端是否做了10次读取,如果不是,就出现粘包或者拆包的情况,这里我们使用byte类型来传输案例如下。

第一步:编写Netty服务端

public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();

        bootstrap.group(bossGroup, workGroup);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childHandler(new ChannelInitializer() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                //添加handler
                pipeline.addLast(new ServerHandler());
            }
        });
        try {
            ChannelFuture sync = bootstrap.bind(3000).sync();
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

第二步:编写服务端handler

public class ServerHandler extends SimpleChannelInboundHandler {

    //服务端接收次数
    private int num = 0;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {

        System.out.println("接收消息,次数 = "+ num++);
        //接收数据
        byte[] bytes = new byte[msg.readableBytes()];
        //把数据读到bytes中
        msg.readBytes(bytes);
        System.out.println(new String(bytes, CharsetUtil.UTF_8));
    }

}

这里定义了一个num来记录服务端数据读取次数。

第三步:定义Netty客户端

public static void main(String[] args) {
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(eventLoopGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.handler(new ChannelInitializer() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new ClientHandler());
            }
        });
        ChannelFuture sync = null;
        try {
            sync = bootstrap.connect("127.0.0.1", 3000).sync();
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            eventLoopGroup.shutdownGracefully();
        }
    }

第四步:定义客户端的Handler

public class ClientHandler extends SimpleChannelInboundHandler {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //发送10个数据块
        for (int i = 0; i             
关注
打赏
1651329177
查看更多评论
0.0766s