日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

概述

本文介紹什么是 TCP 粘包和拆包現(xiàn)象,并通過 Netty 編寫詳細(xì)的案例來重現(xiàn) TCP 粘包問題,最后再通過一個(gè) Netty 的 demo 來解決這個(gè)問題。具體內(nèi)容如下

  1. 什么是 TCP 粘包和拆包現(xiàn)象
  2. 重現(xiàn) TCP 粘包和拆包現(xiàn)象
  3. Netty 解決 TCP 粘包和拆包現(xiàn)象帶來的問題

什么是 TCP 粘包和拆包現(xiàn)象

TCP 編程底層都有粘包和拆包機(jī)制,因?yàn)槲覀冊(cè)贑/S這種傳輸模型下,以TCP協(xié)議傳輸?shù)臅r(shí)候,在網(wǎng)絡(luò)中的byte其實(shí)就像是河水,TCP就像一個(gè)搬運(yùn)工,將這流水從一端轉(zhuǎn)送到另一端,這時(shí)又分兩種情況:

  1. 如果客戶端的每次制造的水比較多,也就是我們常說的客戶端給的包比較大,TCP這個(gè)搬運(yùn)工就會(huì)分多次去搬運(yùn)
  2. 如果客戶端每次制造的水比較少的話,TCP可能會(huì)等客戶端多次生產(chǎn)之后,把所有的水一起再運(yùn)輸?shù)搅硪欢?/li>
  • 對(duì)于第一種情況,TCP 會(huì)再客戶端先進(jìn)行拆包,在另一端接收的時(shí)候,需要把多次獲取的結(jié)果組合在一起,變成我們可以理解的信息
  • 對(duì)于第二種情況,TCP 會(huì)在客戶端先進(jìn)行粘包,在另一端接收的時(shí)候,就必須進(jìn)行拆包處理,因?yàn)槊看谓邮盏男畔?,可能是另一個(gè)遠(yuǎn)程端多次發(fā)送的包,被TCP粘在一起的

重現(xiàn) TCP 粘包和拆包現(xiàn)象

  1. 通過在客戶端 1 次發(fā)送超大數(shù)據(jù)包給服務(wù)器端來重現(xiàn) TCP 拆包現(xiàn)象
  2. 通過在客戶端分 10 次發(fā)送較小的數(shù)據(jù)包給服務(wù)器端來重現(xiàn) TCP 粘包現(xiàn)象

下面通過 Netty 重現(xiàn) TCP 粘包和拆包現(xiàn)象。

Netty maven 依賴

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

通過 Netty 重現(xiàn) TCP 拆包現(xiàn)象

  1. Netty 客戶端啟動(dòng)類: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("連接服務(wù)器端:%s:%s 成功!", HOST, PORT));
            }).await();
        } catch (Exception e) {
            log.error("啟動(dòng)客戶端出現(xiàn)異常", 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);

    //客戶端讀取服務(wù)器發(fā)送的信息
    @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("客戶端接收到消息的次數(shù):%s", countRef.accumulateAndGet(1, Integer::sum)));
        log.info("---------------------------------------------------");
    }

    // 重寫 channelActive, 當(dāng)客戶端啟動(dòng)的時(shí)候 自動(dòng)發(fā)送數(shù)據(jù)給服務(wù)端
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 客戶端只發(fā)送一次,但是本次數(shù)據(jù)量很大
        // tcp 會(huì)將數(shù)據(jù)拆分成多份后依次進(jìn)行發(fā)送
        String data = "ckjava";
        StringBuilder stringBuilder = new StringBuilder(data);
        for (int i = 0; i < 10000; i++) {
            stringBuilder.Append(data);
        }
        ByteBuf buffer = Unpooled.copiedBuffer("數(shù)據(jù)" + stringBuilder.toString(), StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer);
    }

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

}

其中關(guān)鍵的代碼如下

 // 重寫 channelActive, 當(dāng)客戶端啟動(dòng)的時(shí)候 自動(dòng)發(fā)送數(shù)據(jù)給服務(wù)端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // 客戶端只發(fā)送一次,但是本次數(shù)據(jù)量很大
    // tcp 會(huì)將數(shù)據(jù)拆分成多份后依次進(jìn)行發(fā)送
    String data = "ckjava";
    StringBuilder stringBuilder = new StringBuilder(data);
    for (int i = 0; i < 10000; i++) {
        stringBuilder.append(data);
    }
    ByteBuf buffer = Unpooled.copiedBuffer("數(shù)據(jù)" + stringBuilder.toString(), StandardCharsets.UTF_8);
    ctx.writeAndFlush(buffer);
}
  1. Netty 客戶端啟動(dòng)類: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);
            // 綁定端口,開始接收進(jìn)來的連接
            sbs.bind(port).addListener(future -> {
                log.info(String.format("服務(wù)器端啟動(dòng)成功,開放端口:%s", port));
            });
        } catch (Exception e) {
            log.error("啟動(dòng)服務(wù)器端出現(xiàn)異常", e);
        }
    }

    public static void main(String[] args) {
        int port = 8080;
        new NettyServer(port).start();
    }
}
  1. Netty 服務(wù)器端通道處理類: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轉(zhuǎn)為字符串
        String message = new String(buffer, StandardCharsets.UTF_8);
        System.out.println("服務(wù)器收到的數(shù)據(jù)=" + message);
        System.out.println("服務(wù)器收到的數(shù)據(jù)次數(shù)=" + (++this.count));

        //服務(wù)器回送數(shù)據(jù)給客戶端 回送一個(gè)隨機(jī)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. 分別先啟動(dòng)服務(wù)器端后,再啟動(dòng)客戶端,服務(wù)器端的輸出如下
詳解什么是 TCP 粘包和拆包現(xiàn)象并演示 Netty 是如何解決的

 

  1. 客戶端的輸出如下
17:03:24.474 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.client.NettyClient - 連接服務(wù)器端: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 - 客戶端接收到消息的次數(shù):1
17:03:24.537 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
  1. 從服務(wù)器端和客戶端的輸出結(jié)果來看:客戶端只發(fā)送了 1 次數(shù)據(jù),但是服務(wù)器端卻收到了 3 次數(shù)據(jù),說明 tcp 在客戶端拆包后分 3 次發(fā)送了;并且客戶端之后只收到了一次數(shù)據(jù),說明服務(wù)器的回復(fù)數(shù)據(jù)在服務(wù)器端也出現(xiàn)了粘包現(xiàn)象,并且導(dǎo)致了數(shù)據(jù)無法區(qū)分的問題。

通過 Netty 重現(xiàn) TCP 粘包現(xiàn)象

  1. 還用上面的例子,將客戶端通道處理類:NettyClientHandler 中的 channelActive 方法修改成如下的方式
// 重寫 channelActive, 當(dāng)客戶端啟動(dòng)的時(shí)候 自動(dòng)發(fā)送數(shù)據(jù)給服務(wù)端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // 使用客戶端分10次發(fā)送,每次數(shù)據(jù)量少
    // tcp 會(huì)等客戶端多次生產(chǎn)后,一次性進(jìn)行發(fā)送
    for (int i = 0; i < 10; i++) {
        ByteBuf buffer = Unpooled.copiedBuffer("ckjava" + i + " ", StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer);
    }
}
  1. 分別先啟動(dòng)服務(wù)器端后,再啟動(dòng)客戶端,服務(wù)器端的輸出如下
17:12:27.239 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.server.NettyServer - 服務(wù)器端啟動(dòng)成功,開放端口:8080
服務(wù)器收到的數(shù)據(jù)=ckjava0 ckjava1 ckjava2 ckjava3 ckjava4 ckjava5 ckjava6 ckjava7 ckjava8 ckjava9 
服務(wù)器收到的數(shù)據(jù)次數(shù)=1
  1. 客戶端的輸出如下
17:12:36.917 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.client.NettyClient - 連接服務(wù)器端: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 - 客戶端接收到消息的次數(shù):1
17:12:36.962 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
  1. 從服務(wù)器端和客戶端的輸出結(jié)果來看:客戶端只發(fā)送了 10 次數(shù)據(jù),但是服務(wù)器端卻收到了 1 次數(shù)據(jù),說明 tcp 在客戶端粘包后一次性發(fā)送了全部的數(shù)據(jù)。

Netty 解決 TCP 粘包和拆包現(xiàn)象帶來的問題

TCP 粘包和拆包現(xiàn)象帶來的問題

從上面的案例可以發(fā)現(xiàn)當(dāng)出現(xiàn) TCP 粘包和拆包現(xiàn)象后會(huì)出現(xiàn)下面的問題:

  1. tcp 在粘包的時(shí)候,數(shù)據(jù)混合后,接收方不能正確區(qū)分?jǐn)?shù)據(jù)的頭尾,如果是文件類型的數(shù)據(jù),會(huì)導(dǎo)致文件破壞。
  2. tcp 在拆包的時(shí)候,數(shù)據(jù)拆分后,接收方不能正確區(qū)分?jǐn)?shù)據(jù)的頭尾,導(dǎo)致收到的消息錯(cuò)亂,影響語義。

如何解決 TCP 粘包和拆包現(xiàn)象帶來的問題

由于 TCP 粘包和拆包現(xiàn)象會(huì)導(dǎo)致不能正確區(qū)分?jǐn)?shù)據(jù)的頭尾,那么解決的辦法也挺簡(jiǎn)單的,通過 特殊字符串 來分隔消息體或者使用 定長(zhǎng)消息 就能夠正確區(qū)分?jǐn)?shù)據(jù)的頭尾。

目前的主流解決方式有以下幾種:

  1. 使用定長(zhǎng)消息,Client 和 Server 雙方約定報(bào)文長(zhǎng)度,Server 端接受到報(bào)文后,按指定長(zhǎng)度解析;
  2. 使用特定分隔符,比如在消息尾部增加分隔符。Server 端接收到報(bào)文后,按照特定的分割符分割消息后,再解析;
  3. 將消息分割為消息頭和消息體兩部分,消息頭中指定消息或者消息體的長(zhǎng)度,通常設(shè)計(jì)中使用消息頭第一個(gè)字段 int32 表示消息體的總長(zhǎng)度;

Netty 中也提供了基于分隔符實(shí)現(xiàn)的半包解碼器和定長(zhǎng)的半包解碼器:

  1. LineBasedFrameDecoder 使用"n"和"rn"作為分割符的解碼器
  2. DelimiterBasedFrameDecoder 使用自定義的分割符的解碼器
  3. FixedLengthFrameDecoder 定長(zhǎng)解碼器

通過 Netty 的 DelimiterBasedFrameDecoder 解碼器 來解決 TCP 粘包和拆包現(xiàn)象帶來的問題

使用
DelimiterBasedFrameDecoder 可以確保收到的數(shù)據(jù)會(huì)自動(dòng)通過 自定義的分隔符 進(jìn)行分隔。發(fā)送的時(shí)候消息的后面只需要增加上 自定義的分隔符 即可。

  1. 基于上面的例子,服務(wù)器端 NettyServer 改動(dòng)如下
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);
        // 綁定端口,開始接收進(jìn)來的連接
        sbs.bind(port).addListener(future -> {
            log.info(String.format("服務(wù)器端啟動(dòng)成功,開放端口:%s", port));
        });
    } catch (Exception e) {
        log.error("啟動(dòng)服務(wù)器端出現(xiàn)異常", e);
    }
}
  1. 服務(wù)器端 NettyServerHandler 改動(dòng)如下
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
    byte[] buffer = new byte[msg.readableBytes()];
    msg.readBytes(buffer);
    //將buffer轉(zhuǎn)為字符串
    String message = new String(buffer, StandardCharsets.UTF_8);
    System.out.println("服務(wù)器收到的數(shù)據(jù)=" + message);
    System.out.println("服務(wù)器收到的數(shù)據(jù)次數(shù)=" + (++this.count));

    //服務(wù)器回送數(shù)據(jù)給客戶端 回送一個(gè)隨機(jī)id
    String replyData = UUID.randomUUID().toString();
    ByteBuf buffer1 = Unpooled.copiedBuffer(replyData.concat(NettyServer.DELIMITER), StandardCharsets.UTF_8);
    ctx.writeAndFlush(buffer1);
    System.out.println("服務(wù)器回復(fù)數(shù)據(jù)=" + replyData);
}
  1. 客戶端 NettyClient 改動(dòng)如下
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("連接服務(wù)器端:%s:%s 成功!", HOST, PORT));
        }).await();
    } catch (Exception e) {
        log.error("啟動(dòng)客戶端出現(xiàn)異常", e);
    }
}
  1. 客戶端 NettyClientHandler 中接收數(shù)據(jù)的部分不變,發(fā)送數(shù)據(jù)的地方改動(dòng)如下
// 重寫 channelActive, 當(dāng)客戶端啟動(dòng)的時(shí)候 自動(dòng)發(fā)送數(shù)據(jù)給服務(wù)端
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    // tcp 粘包現(xiàn)象
    // 使用客戶端分10次發(fā)送,每次數(shù)據(jù)量少
    // tcp 會(huì)等客戶端多次生產(chǎn)后,一次性進(jìn)行發(fā)送
    for (int i = 0; i < 10; i++) {
        String data = "ckjava" + i;
        log.info(String.format("客戶端發(fā)送消息:[%s]", data));
        ByteBuf buffer = Unpooled.copiedBuffer(data.concat(NettyClient.DELIMITER), StandardCharsets.UTF_8);
        ctx.writeAndFlush(buffer);
    }
}
  1. 服務(wù)器端輸出如下
18:14:33.627 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.server.NettyServer - 服務(wù)器端啟動(dòng)成功,開放端口:8080
服務(wù)器收到的數(shù)據(jù)=ckjava0
服務(wù)器收到的數(shù)據(jù)次數(shù)=1
服務(wù)器回復(fù)數(shù)據(jù)=c6129b89-c869-4e06-97ca-55518c55aff7
服務(wù)器收到的數(shù)據(jù)=ckjava1
服務(wù)器收到的數(shù)據(jù)次數(shù)=2
服務(wù)器回復(fù)數(shù)據(jù)=bc3426cb-072f-4cb9-9f69-d2797863c9e4
服務(wù)器收到的數(shù)據(jù)=ckjava2
服務(wù)器收到的數(shù)據(jù)次數(shù)=3
服務(wù)器回復(fù)數(shù)據(jù)=43790702-1978-462b-a865-15c0ff2803af
服務(wù)器收到的數(shù)據(jù)=ckjava3
服務(wù)器收到的數(shù)據(jù)次數(shù)=4
服務(wù)器回復(fù)數(shù)據(jù)=4eb3e4e6-0c6a-4cef-a639-d6c40ebc27d2
服務(wù)器收到的數(shù)據(jù)=ckjava4
服務(wù)器收到的數(shù)據(jù)次數(shù)=5
服務(wù)器回復(fù)數(shù)據(jù)=6a9f02f9-9e0d-4eae-a380-605c3ba410d2
服務(wù)器收到的數(shù)據(jù)=ckjava5
服務(wù)器收到的數(shù)據(jù)次數(shù)=6
服務(wù)器回復(fù)數(shù)據(jù)=7ab9e20e-a86b-4f68-8673-5bc024643274
服務(wù)器收到的數(shù)據(jù)=ckjava6
服務(wù)器收到的數(shù)據(jù)次數(shù)=7
服務(wù)器回復(fù)數(shù)據(jù)=3b6b68cf-c066-4e32-8b5a-961c995fdd6d
服務(wù)器收到的數(shù)據(jù)=ckjava7
服務(wù)器收到的數(shù)據(jù)次數(shù)=8
服務(wù)器回復(fù)數(shù)據(jù)=cf2a5c51-96d9-4309-8f05-1c09abbe04f2
服務(wù)器收到的數(shù)據(jù)=ckjava8
服務(wù)器收到的數(shù)據(jù)次數(shù)=9
服務(wù)器回復(fù)數(shù)據(jù)=4d586684-be55-4c10-8071-a88dad5f0684
服務(wù)器收到的數(shù)據(jù)=ckjava9
服務(wù)器收到的數(shù)據(jù)次數(shù)=10
服務(wù)器回復(fù)數(shù)據(jù)=22fd511e-e65a-4f10-9426-f14b4524d4d0
  1. 客戶端輸出如下
18:14:50.056 [nioEventLoopGroup-2-1] INFO  com.ckjava.test.client.NettyClient - 連接服務(wù)器端:127.0.0.1:8080 成功!
18:14:50.058 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava0]
18:14:50.075 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava1]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava2]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava3]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava4]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava5]
18:14:50.076 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava6]
18:14:50.077 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava7]
18:14:50.077 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[ckjava8]
18:14:50.077 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - 客戶端發(fā)送消息:[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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):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 - 客戶端接收到消息的次數(shù):10
18:14:50.107 [nioEventLoopGroup-2-1] INFO  c.c.test.client.NettyClientHandler - ---------------------------------------------------
  1. 從上面的例子可以看出 DelimiterBasedFrameDecoder 會(huì)幫自動(dòng)幫我們把消息切割好,確保收到的數(shù)據(jù)都是基于 自定義分隔符 分隔好的數(shù)據(jù),但是不要忘記在發(fā)送數(shù)據(jù)的時(shí)候添加上 自定義分隔符

分享到:
標(biāo)簽:TCP
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定