Netty粘包拆包问题说明、演示拆包粘包情况代码以及解决

本文围绕Netty网络通信展开,介绍了TCP传输中因无消息保护边界导致的粘包、拆包问题。通过实例和演示展示了粘包、拆包现象,最后提出使用自定义协议加编码解码器的解决方案,经测试成功解决了粘包和拆包问题。
概述

TCP传输协议是面向连接的,面向流提供高可靠的服务。收发两端(服务端和客户端)都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效地发给对方,使用了优化算法(Nagle算法),将多次间隔时间较小且数据较小的数据包,合成一个大的数据块,然后进行封包,这样做虽然提高了传输的效率,但是这样接收端就难以分辨出一个个完整的包的大小了,因为面向流的通信时无消息保护边界的。

由于TCP无消息保护边界,需要在接收端处理消息边界问题,也就是粘包、拆包问题。

示意图:
在这里插入图片描述
说明:

  1. 服务端给客户端发送D1、D2两个数据包。
  2. 第一种情况是服务端两次都读取到的是两个独立的数据包,无拆包粘包问题,可以正常解析。
  3. 第二种情况D1、D2包合并在一起一次发送,服务端一次性接收了两个数据包,分别是D1、D2,我们称之为粘包,因为不知道边界,所以服务端不知如何拆出来解析。
  4. 第三种情况,服务端第一次接收到了完整D1包和部分D2包,第二次接收到了剩余的D2包,D2包被拆开来分多次发送了,我们称之为拆包。
  5. 第四种情况,服务端第一次接收到了部分D1包,第二次接收到了剩余部分D1包和完整D2包,也称之为拆包。

总的来说拆包和粘包问题,因为没有边界,最终会在正常情况下导致接收方无法分辨出一个一个包。

粘包实例

以下实例证实了粘包的存在:
服务端及服务端的Handler:

public class NettyTcpServer {
   
   


    private  int port;

    public NettyTcpServer(int port){
   
   
        this.port = port;
    }


    public void start() throws InterruptedException {
   
   

        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();

        serverBootstrap.group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
   
   
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
   
   
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new NettyTcpServerChannelHandler());
                    }
                });

        ChannelFuture channelFuture = serverBootstrap.bind(port);
        channelFuture.channel().closeFuture().sync();
    }

    public static void main(String[] args) throws InterruptedException {
   
   
        NettyTcpServer nettyTcpServer = new NettyTcpServer(8989);
        nettyTcpServer.start();
    }
}


public class NettyTcpServerChannelHandler extends ChannelInboundHandlerAdapter {
   
   

    private int count;
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   
   
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("数据是:" + byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("count = " + (++count));
        super.channelRead(ctx, msg);
    }
}

客户端及客户端的Handler

public class NettyTcpClient {
   
   

    private  int serverPort;


    public NettyTcpClient(int serverPort){
   
   
        this.serverPort = serverPort;
    }

    public void start() throws InterruptedException {
   
   
        NioEventLoopGroup worker = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值