您当前的位置:首页 > 电脑百科 > 网络技术 > 网络知识

详解什么是 TCP 粘包和拆包现象并演示 Netty 是如何解决的

时间:2022-04-24 11:07:06  来源:  作者:ckjava

概述

本文介绍什么是 TCP 粘包和拆包现象,并通过.NETty 编写详细的案例来重现 TCP 粘包问题,最后再通过一个 Netty 的 demo 来解决这个问题。具体内容如下

  1. 什么是 TCP 粘包和拆包现象
  2. 重现 TCP 粘包和拆包现象
  3. Netty 解决 TCP 粘包和拆包现象带来的问题

什么是 TCP 粘包和拆包现象

TCP 编程底层都有粘包和拆包机制,因为我们在C/S这种传输模型下,以TCP协议传输的时候,在网络中的byte其实就像是河水,TCP就像一个搬运工,将这流水从一端转送到另一端,这时又分两种情况:

  1. 如果客户端的每次制造的水比较多,也就是我们常说的客户端给的包比较大,TCP这个搬运工就会分多次去搬运
  2. 如果客户端每次制造的水比较少的话,TCP可能会等客户端多次生产之后,把所有的水一起再运输到另一端
  • 对于第一种情况,TCP 会再客户端先进行拆包,在另一端接收的时候,需要把多次获取的结果组合在一起,变成我们可以理解的信息
  • 对于第二种情况,TCP 会在客户端先进行粘包,在另一端接收的时候,就必须进行拆包处理,因为每次接收的信息,可能是另一个远程端多次发送的包,被TCP粘在一起的

重现 TCP 粘包和拆包现象

  1. 通过在客户端 1 次发送超大数据包给服务器端来重现 TCP 拆包现象
  2. 通过在客户端分 10 次发送较小的数据包给服务器端来重现 TCP 粘包现象

下面通过 Netty 重现 TCP 粘包和拆包现象。

Netty maven 依赖

<dependency>
	<groupId>io.netty</groupId>
	<artifactId>netty-all</artifactId>
	<version>4.1.76.Final</version>
</dependency>

通过 Netty 重现 TCP 拆包现象

  1. Netty 客户端启动类:NettyClient
package com.ckJAVA.test.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class NettyClient {
    static final String HOST = System.getProperty("host", "127.0.0.1");
    static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
    static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));

    public static void mAIn(String[] args) throws Exception {
        // 初始化客户端事件组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    // 初始化通道
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        // 初始化通道处理器
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new NettyClientHandler());
                        }
                    });

            b.connect(HOST, PORT).addListener(future -> {
                log.info(String.format("连接服务器端:%s:%s 成功!", HOST, PORT));
            }).await();
        } catch (Exception e) {
            log.error("启动客户端出现异常", e);
        }
    }
}
  1. Netty 客户端通道处理类:NettyClientHandler
package com.ckjava.test.client;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    private final AtomicInteger countRef = new AtomicInteger(0);

    //客户端读取服务器发送的信息
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        byte[] buffer = new byte[msg.readableBytes()];
        msg.readBytes(buffer);
        String message = new String(buffer, StandardCharsets.UTF_8);
        log.info(String.format("客户端接收到消息:[%s]", message));
        log.info(String.format("客户端接收到消息的次数:%s", countRef.accumulateAndGet(1, Integer::sum)));
        log.info("---------------------------------------------------");
    }

    // 重写 channelActive, 当客户端启动的时候 自动发送数据给服务端
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 客户端只发送一次,但是本次数据量很大
        // tcp 会将数据拆分成多份后依次进行发送
        String data = "ckjava";
        StringBuilder stringBuilder = new StringBuilder(data);
        for (int i = 0; i < 10000; i++) {
            stringBuilder.Append(data);
        }
        ByteBuf buffer = Unpooled.copiedBuffer("数据" + stringBuilder.toString(), StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }

}

其中关键的代码如下

 // 重写 channelActive, 当客户端启动的时候 自动发送数据给服务端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // 客户端只发送一次,但是本次数据量很大
    // tcp 会将数据拆分成多份后依次进行发送
    String data = "ckjava";
    StringBuilder stringBuilder = new StringBuilder(data);
    for (int i = 0; i < 10000; i++) {
        stringBuilder.append(data);
    }
    ByteBuf buffer = Unpooled.copiedBuffer("数据" + stringBuilder.toString(), StandardCharsets.UTF_8);
    ctx.writeAndFlush(buffer);
}
  1. Netty 客户端启动类:NettyClient
package com.ckjava.test.server;

import io.netty.bootstrap.ServerBootstrap;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

@Slf4j
@Component
public class NettyServer {

    private final int port;

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

    public void start() {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap sbs = new ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new NettyServerHandler());
                        }
                    }).option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定端口,开始接收进来的连接
            sbs.bind(port).addListener(future -> {
                log.info(String.format("服务器端启动成功,开放端口:%s", port));
            });
        } catch (Exception e) {
            log.error("启动服务器端出现异常", e);
        }
    }

    public static void main(String[] args) {
        int port = 8080;
        new NettyServer(port).start();
    }
}
  1. Netty 服务器端通道处理类:NettyServer
package com.ckjava.test.server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<ByteBuf> {

    private int counter;

    private int count;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
        byte[] buffer = new byte[msg.readableBytes()];
        msg.readBytes(buffer);
        //将buffer转为字符串
        String message = new String(buffer, StandardCharsets.UTF_8);
        System.out.println("服务器收到的数据=" + message);
        System.out.println("服务器收到的数据次数=" + (++this.count));

        //服务器回送数据给客户端 回送一个随机id
        ByteBuf buffer1 = Unpooled.copiedBuffer(UUID.randomUUID().toString(), StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer1);
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

}
  1. 分别先启动服务器端后,再启动客户端,服务器端的输出如下
详解什么是 TCP 粘包和拆包现象并演示 Netty 是如何解决的

 

  1. 客户端的输出如下
17:03:24.474 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.client.NettyClient - 连接服务器端:127.0.0.1:8080 成功!
17:03:24.535 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[c471a239-abe5-4401-93aa-b3d5e432c422021b6ae3-4939-4d59-b451-235af6c9e2190536b0aa-3b53-4b03-bb68-b0637d619d0f]
17:03:24.537 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:1
17:03:24.537 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
  1. 从服务器端和客户端的输出结果来看:客户端只发送了 1 次数据,但是服务器端却收到了 3 次数据,说明 tcp 在客户端拆包后分 3 次发送了;并且客户端之后只收到了一次数据,说明服务器的回复数据在服务器端也出现了粘包现象,并且导致了数据无法区分的问题。

通过 Netty 重现 TCP 粘包现象

  1. 还用上面的例子,将客户端通道处理类:NettyClientHandler 中的 channelActive 方法修改成如下的方式
// 重写 channelActive, 当客户端启动的时候 自动发送数据给服务端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // 使用客户端分10次发送,每次数据量少
    // tcp 会等客户端多次生产后,一次性进行发送
    for (int i = 0; i < 10; i++) {
        ByteBuf buffer = Unpooled.copiedBuffer("ckjava" + i + " ", StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer);
    }
}
  1. 分别先启动服务器端后,再启动客户端,服务器端的输出如下
17:12:27.239 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.server.NettyServer - 服务器端启动成功,开放端口:8080
服务器收到的数据=ckjava0 ckjava1 ckjava2 ckjava3 ckjava4 ckjava5 ckjava6 ckjava7 ckjava8 ckjava9 
服务器收到的数据次数=1
  1. 客户端的输出如下
17:12:36.917 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.client.NettyClient - 连接服务器端:127.0.0.1:8080 成功!
17:12:36.961 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[31b25c25-bd32-4ff1-b390-0c31b2558d12]
17:12:36.962 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:1
17:12:36.962 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
  1. 从服务器端和客户端的输出结果来看:客户端只发送了 10 次数据,但是服务器端却收到了 1 次数据,说明 tcp 在客户端粘包后一次性发送了全部的数据。

Netty 解决 TCP 粘包和拆包现象带来的问题

TCP 粘包和拆包现象带来的问题

从上面的案例可以发现当出现 TCP 粘包和拆包现象后会出现下面的问题:

  1. tcp 在粘包的时候,数据混合后,接收方不能正确区分数据的头尾,如果是文件类型的数据,会导致文件破坏。
  2. tcp 在拆包的时候,数据拆分后,接收方不能正确区分数据的头尾,导致收到的消息错乱,影响语义。

如何解决 TCP 粘包和拆包现象带来的问题

由于 TCP 粘包和拆包现象会导致不能正确区分数据的头尾,那么解决的办法也挺简单的,通过 特殊字符串 来分隔消息体或者使用 定长消息 就能够正确区分数据的头尾。

目前的主流解决方式有以下几种:

  1. 使用定长消息,Client 和 Server 双方约定报文长度,Server 端接受到报文后,按指定长度解析;
  2. 使用特定分隔符,比如在消息尾部增加分隔符。Server 端接收到报文后,按照特定的分割符分割消息后,再解析;
  3. 将消息分割为消息头和消息体两部分,消息头中指定消息或者消息体的长度,通常设计中使用消息头第一个字段 int32 表示消息体的总长度;

Netty 中也提供了基于分隔符实现的半包解码器和定长的半包解码器:

  1. LineBasedFrameDecoder 使用"n"和"rn"作为分割符的解码器
  2. DelimiterBasedFrameDecoder 使用自定义的分割符的解码器
  3. FixedLengthFrameDecoder 定长解码器

通过 Netty 的 DelimiterBasedFrameDecoder 解码器 来解决 TCP 粘包和拆包现象带来的问题

使用
DelimiterBasedFrameDecoder 可以确保收到的数据会自动通过 自定义的分隔符 进行分隔。发送的时候消息的后面只需要增加上 自定义的分隔符 即可。

  1. 基于上面的例子,服务器端 NettyServer 改动如下
public void start() {
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
        ServerBootstrap sbs = new ServerBootstrap()
                .group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .localAddress(new InetSocketAddress(port))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel ch) {
                        // 使用分隔符"$_"的半包解码器
                        ByteBuf byteBuf = Unpooled.copiedBuffer(DELIMITER.getBytes());
                        ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, byteBuf));
                        ch.pipeline().addLast(new NettyServerHandler());
                    }
                }).option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        // 绑定端口,开始接收进来的连接
        sbs.bind(port).addListener(future -> {
            log.info(String.format("服务器端启动成功,开放端口:%s", port));
        });
    } catch (Exception e) {
        log.error("启动服务器端出现异常", e);
    }
}
  1. 服务器端 NettyServerHandler 改动如下
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
    byte[] buffer = new byte[msg.readableBytes()];
    msg.readBytes(buffer);
    //将buffer转为字符串
    String message = new String(buffer, StandardCharsets.UTF_8);
    System.out.println("服务器收到的数据=" + message);
    System.out.println("服务器收到的数据次数=" + (++this.count));

    //服务器回送数据给客户端 回送一个随机id
    String replyData = UUID.randomUUID().toString();
    ByteBuf buffer1 = Unpooled.copiedBuffer(replyData.concat(NettyServer.DELIMITER), StandardCharsets.UTF_8);
    ctx.writeAndFlush(buffer1);
    System.out.println("服务器回复数据=" + replyData);
}
  1. 客户端 NettyClient 改动如下
public static void main(String[] args) throws Exception {
    // 初始化客户端事件组
    EventLoopGroup group = new NioEventLoopGroup();
    try {
        Bootstrap b = new Bootstrap();
        b.group(group)
                // 初始化通道
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    // 初始化通道处理器
                    @Override
                    public void initChannel(SocketChannel ch) {
                        ChannelPipeline p = ch.pipeline();
                        // 使用分隔符"$_"的半包解码器
                        ByteBuf byteBuf = Unpooled.copiedBuffer(DELIMITER.getBytes());
                        ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, byteBuf));
                        p.addLast(new NettyClientHandler());
                    }
                });

        b.connect(HOST, PORT).addListener(future -> {
            log.info(String.format("连接服务器端:%s:%s 成功!", HOST, PORT));
        }).await();
    } catch (Exception e) {
        log.error("启动客户端出现异常", e);
    }
}
  1. 客户端 NettyClientHandler 中接收数据的部分不变,发送数据的地方改动如下
// 重写 channelActive, 当客户端启动的时候 自动发送数据给服务端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // tcp 粘包现象
    // 使用客户端分10次发送,每次数据量少
    // tcp 会等客户端多次生产后,一次性进行发送
    for (int i = 0; i < 10; i++) {
        String data = "ckjava" + i;
        log.info(String.format("客户端发送消息:[%s]", data));
        ByteBuf buffer = Unpooled.copiedBuffer(data.concat(NettyClient.DELIMITER), StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer);
    }
}
  1. 服务器端输出如下
18:14:33.627 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.server.NettyServer - 服务器端启动成功,开放端口:8080
服务器收到的数据=ckjava0
服务器收到的数据次数=1
服务器回复数据=c6129b89-c869-4e06-97ca-55518c55aff7
服务器收到的数据=ckjava1
服务器收到的数据次数=2
服务器回复数据=bc3426cb-072f-4cb9-9f69-d2797863c9e4
服务器收到的数据=ckjava2
服务器收到的数据次数=3
服务器回复数据=43790702-1978-462b-a865-15c0ff2803af
服务器收到的数据=ckjava3
服务器收到的数据次数=4
服务器回复数据=4eb3e4e6-0c6a-4cef-a639-d6c40ebc27d2
服务器收到的数据=ckjava4
服务器收到的数据次数=5
服务器回复数据=6a9f02f9-9e0d-4eae-a380-605c3ba410d2
服务器收到的数据=ckjava5
服务器收到的数据次数=6
服务器回复数据=7ab9e20e-a86b-4f68-8673-5bc024643274
服务器收到的数据=ckjava6
服务器收到的数据次数=7
服务器回复数据=3b6b68cf-c066-4e32-8b5a-961c995fdd6d
服务器收到的数据=ckjava7
服务器收到的数据次数=8
服务器回复数据=cf2a5c51-96d9-4309-8f05-1c09abbe04f2
服务器收到的数据=ckjava8
服务器收到的数据次数=9
服务器回复数据=4d586684-be55-4c10-8071-a88dad5f0684
服务器收到的数据=ckjava9
服务器收到的数据次数=10
服务器回复数据=22fd511e-e65a-4f10-9426-f14b4524d4d0
  1. 客户端输出如下
18:14:50.056 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.client.NettyClient - 连接服务器端:127.0.0.1:8080 成功!
18:14:50.058 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava0]
18:14:50.075 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava1]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava2]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava3]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava4]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava5]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava6]
18:14:50.077 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava7]
18:14:50.077 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava8]
18:14:50.077 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端发送消息:[ckjava9]
18:14:50.104 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[c6129b89-c869-4e06-97ca-55518c55aff7]
18:14:50.105 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:1
18:14:50.105 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.105 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[bc3426cb-072f-4cb9-9f69-d2797863c9e4]
18:14:50.105 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:2
18:14:50.105 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[43790702-1978-462b-a865-15c0ff2803af]
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:3
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[4eb3e4e6-0c6a-4cef-a639-d6c40ebc27d2]
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:4
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[6a9f02f9-9e0d-4eae-a380-605c3ba410d2]
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:5
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[7ab9e20e-a86b-4f68-8673-5bc024643274]
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:6
18:14:50.106 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[3b6b68cf-c066-4e32-8b5a-961c995fdd6d]
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:7
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[cf2a5c51-96d9-4309-8f05-1c09abbe04f2]
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:8
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[4d586684-be55-4c10-8071-a88dad5f0684]
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:9
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息:[22fd511e-e65a-4f10-9426-f14b4524d4d0]
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客户端接收到消息的次数:10
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
  1. 从上面的例子可以看出 DelimiterBasedFrameDecoder 会帮自动帮我们把消息切割好,确保收到的数据都是基于 自定义分隔符 分隔好的数据,但是不要忘记在发送数据的时候添加上 自定义分隔符


Tags:TCP 粘包   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
详解什么是 TCP 粘包和拆包现象并演示 Netty 是如何解决的
概述本文介绍什么是 TCP 粘包和拆包现象,并通过 Netty 编写详细的案例来重现 TCP 粘包问题,最后再通过一个 Netty 的 demo 来解决这个问题。具体内容如下 什么是 TCP 粘包和拆...【详细内容】
2022-04-24  Search: TCP 粘包  点击:(323)  评论:(0)  加入收藏
TCP 粘包、半包 Netty 全搞定
什么是粘包和半包?粘包的主要原因:&bull; 发送方每次写入数据 < 套接字缓冲区大小&bull; 接收方读取套接字缓冲区数据不够及时半包的主要原因:&bull; 发送方写入数据 > 套接字...【详细内容】
2020-10-14  Search: TCP 粘包  点击:(434)  评论:(0)  加入收藏
TCP 粘包和半包 介绍及解决
在网络传输中,粘包和半包应该是最常出现的问题,作为 Java 中最常使用的 NIO 网络框架 Netty,它又是如何解决的呢?今天就让我们来看看。定义TCP 传输中,客户端发送数据,实际是把数...【详细内容】
2019-10-23  Search: TCP 粘包  点击:(722)  评论:(0)  加入收藏
▌简易百科推荐
学生偷看“不良网站”,手机上3个痕迹无法清除,网友:咋不早说
众所周知,中国的常规教育中,总是“谈性色变”,但在这个信息爆炸的互联网时代,即便是一些年纪很小的孩子,也能轻易接触到一些所谓的不良网站,因此这一方面的教育缺失,其实是很可怕的...【详细内容】
2024-03-28    叶姐生活指南  Tags:不良网站   点击:(18)  评论:(0)  加入收藏
什么是网络中的路由器?核心功能解释
路由器是互联网连接的核心元素,是一种允许多个设备连接到互联网,并促进将数据包转发到各自的目标地址的设备。使用动态路由技术,路由器检查数据并在各种可用路径中选择最有效的...【详细内容】
2024-03-07    千家网  Tags:路由器   点击:(34)  评论:(0)  加入收藏
过年该不该升级Wi-Fi 7路由?看完就知道
打开电商网站不难发现,从2023年第三季度到现在,Wi-Fi 7路由器新品越来越多。而且价格不再是高高在上,已经基本和Wi-Fi 6路由价格差不多了。看到这些Wi-Fi 7新品路由,不少朋友就...【详细内容】
2024-02-27    中关村在线  Tags:Wi-Fi   点击:(44)  评论:(0)  加入收藏
聊聊 Kubernetes 网络模型综合指南
这篇详细的博文探讨了 Kubernetes 网络的复杂性,提供了关于如何在容器化环境中确保高效和安全通信的见解。译自Navigating the Network: A Comprehensive Guide to Kubernete...【详细内容】
2024-02-19  云云众生s  微信公众号  Tags:Kubernetes   点击:(42)  评论:(0)  加入收藏
SSL协议是什么?关于SSL和TLS的常见问题解答
SSL(安全套接字层)及其后继者TLS(传输层安全)是用于在联网计算机之间建立经过身份验证和加密的链接的协议。尽管SSL协议在 1999年已经随着TLS 1.0的发布而被弃用,但我们仍将这些...【详细内容】
2024-02-06  IDC点评网    Tags:SSL协议   点击:(73)  评论:(0)  加入收藏
从零开始了解网络协议:TCP/IP详解
从零开始了解网络协议:TCP/IP详解 在当今数字化的时代,网络协议已经成为我们生活中不可或缺的一部分。作为互联网的基础,网络协议规定了数据如何在不同的网络设备之间传输。TC...【详细内容】
2024-02-01    简易百科  Tags:TCP/IP   点击:(62)  评论:(0)  加入收藏
BGP路由属性:互联网路由的灵活控制器
在互联网的庞大网络中,边界网关协议(BGP)是确保不同自治系统(AS)间路由信息有效交换的关键协议。然而,BGP的功能远不止于此。其核心组成部分,即BGP路由属性,赋予了BGP强大的灵活性,使...【详细内容】
2024-01-26  诺诺爱生活    Tags:互联网路由   点击:(44)  评论:(0)  加入收藏
简易百科之什么是网络延迟?
简易百科之什么是网络延迟?随着互联网的普及和发展,网络已经成为我们生活中不可或缺的一部分。然而,我们在使用网络时可能会遇到一种情况,那就是网络延迟。那么,什么是网络延迟呢...【详细内容】
2024-01-24    简易百科  Tags:网络延迟   点击:(161)  评论:(0)  加入收藏
网络延迟与网络速度有什么区别?分享具体的答案
通常,许多人抱怨网速测试。速度还是不错的,但是他们玩游戏的时候怎么会卡住,还是断开连接等等问题,这一系列问题始终困扰着大家。那么,网络延迟与网络速度有什么区别呢?请不要担心...【详细内容】
2024-01-24  萌新小郭    Tags:网络延迟   点击:(53)  评论:(0)  加入收藏
揭秘IP地址的网络威胁与攻击类型
在当今数字化时代,网络攻击已经成为网络安全的一大挑战。IP地址,作为互联网通信的基础,也成为网络威胁和攻击的焦点之一。本文将深入探讨不同类型的网络威胁和攻击,以及如何防范...【详细内容】
2024-01-22  IP数据云    Tags:IP地址   点击:(86)  评论:(0)  加入收藏
站内最新
站内热门
站内头条