<netty权威指南>笔记-以回车换行结尾的消息如何处理半包问题

原创 2017年09月01日 23:28:36

概述


TCP底层会发生粘包和拆包,这个是TCP的一个特性。为了减少网络数据传输的次数,TCP总是希望让网络数据到达一定量级的时候才将数据发送出去,而不是缓存区一有数据就马上发送数据。

TCP底层会根据缓冲区是否被填满了,来决定是否发送数据。但是从业务层面上看,这个是不合理的。因为一份业务数据可能很小,还不足以填满缓冲区,这样底层TCP就不会立刻把这份业务数据发送出去,而是等到好几份业务数据的大小填满缓冲区后才发送。这样子无论是服务端还是客户端,接收数据的时候可能会处理出错。

如果是以回车换行结尾的消息,那么组合使用

LineBasedFrameDecoder
StringDecoder

来处理半包问题。


TCP粘包拆包重现

李林锋的《netty权威指南》详细说明了TCP的粘包和拆包问题,下面就用netty权威指南》的例子作为demo。


服务端代码

package tcp.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class SocketServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        EventLoopGroup childGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new SocketServerInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        }
        finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }
}


package tcp.server;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;


public class SocketServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new SocketServerHandler());
    }
}


package tcp.server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;

public class SocketServerHandler extends ChannelInboundHandlerAdapter {
    private int counter;
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf)msg;
        byte[] req = new byte[buf.readableBytes()];
        //将buf中的数据读取到req中
        buf.readBytes(req);

        //打印客户端发送的数据
        String body = new String(req, "UTF-8").substring(0, req.length - 1);
        System.out.println("server receive order:"+body+";the counter is:"+ ++counter);

        String currentTime = "";
        if ("QUERY TIME ORDER".equalsIgnoreCase(body)) {
            currentTime = new Date(System.currentTimeMillis()).toString();
        }
        else {
            currentTime = "BAD ORDER";
        }

        String separator = "\n";
        currentTime = currentTime + separator;

        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.writeAndFlush(resp);
    }
}

客户端代码

package tcp.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class SocketClient {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new SocketClientInitializer());

            ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
            channelFuture.channel().closeFuture().sync();
        }
        finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}

package tcp.client;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;

public class SocketClientInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new SocketClientHandler());
    }
}

package tcp.client;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class SocketClientHandler extends ChannelInboundHandlerAdapter {
    private int counter;
    private byte[] req;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf)msg;
        byte[] req = new byte[buf.readableBytes()];

        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("Now is : " + body + " ; the counter is :"+ ++counter);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf message = null;
        for (int i = 0; i < 100; i++) {
            message = Unpooled.buffer(req.length);
            message.writeBytes(req);
            ctx.writeAndFlush(message);
        }
    }

    public SocketClientHandler() {
      req = ("QUERY TIME ORDER" + "\n").getBytes();
    }
}

当客户端与服务端建立完连接后,客户端中的SocketClientHandler类中的

channelActive

方法会被调用,往服务端发送100次请求,每个请求的内容都是

“QUERY TIME ORDER” + “\n”

当服务端接收到这些请求时,SocketServerHandler类中的

channelRead

方法会被调用,接到客户端发送的消息,如果每次收到的消息都是

QUERY TIME ORDER

那么服务端会往客户端输出当前时间。

当客户端接收到服务端的请求后,客户端类SocketClientHandler的

channelRead

方法会被调用,输出服务端返回的数据。

理论上,我们是希望客户端发送100次请求,服务端响应后,也发送100次响应。但实际上,客户端只发送了两次请求,同时服务端响应客户端的时候,只是发送了一次请求。

服务端真实打印的信息如下

server receive order:QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUE;the counter is:1
server receive order:Y TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER;the counter is:2

注意分析上面的输出,从

server receive order:QUERY TIME ORDER

到第一个

the counter is:1

中间有非常多的

QUERY TIME ORDER

说明客户端虽然发送了100次请求,但其实是累积了很多数据后,才真正的发送了一次数据。结果100次调用,最终只给服务端发送了两次请求。

既然服务端只是接收了2次请求,那么应该也给客户端发送两次请求,但是事实上只发送了一次,客户端的输出结果如下

Now is : BAD ORDER
BAD ORDER
 ; the counter is :1

有两个

BAD ORDER

说明服务端只给客户端发送了一次请求。

到此我们得出结论,在这个例子中

客户端和服务端都发送了粘包


netty自带的解码器解决粘包和拆包问题


可以使用自带的

LineBasedFrameDecoder和StringDecoder

解码器来解决这个问题,我们稍微调整一下代码。

在SocketServerInitializer类中加入

pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());

在SocketClientInitializer类中也加入

pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());

将SocketServerHandler类channelRead方法中的

ByteBuf buf = (ByteBuf)msg;
byte[] req = new byte[buf.readableBytes()];
//将buf中的数据读取到req中
 buf.readBytes(req);

 //打印客户端发送的数据
 String body = new String(req, "UTF-8").substring(0, req.length - 1);

用下面一行代码替换即可

String body = (String)msg;

同样也将SocketClientHandler类中channelRead方法中的

 ByteBuf buf = (ByteBuf)msg;
 byte[] req = new byte[buf.readableBytes()];

 buf.readBytes(req);
 String body = new String(req, "UTF-8");

换成

String body = (String)msg;

接下来运行服务端和客户端,发现输出结果已经正常了。
服务端输出

server receive order:QUERY TIME ORDER;the counter is:1
server receive order:QUERY TIME ORDER;the counter is:2
server receive order:QUERY TIME ORDER;the counter is:3
server receive order:QUERY TIME ORDER;the counter is:4
server receive order:QUERY TIME ORDER;the counter is:5
server receive order:QUERY TIME ORDER;the counter is:6
server receive order:QUERY TIME ORDER;the counter is:7
server receive order:QUERY TIME ORDER;the counter is:8
server receive order:QUERY TIME ORDER;the counter is:9
server receive order:QUERY TIME ORDER;the counter is:10
server receive order:QUERY TIME ORDER;the counter is:11
server receive order:QUERY TIME ORDER;the counter is:12
server receive order:QUERY TIME ORDER;the counter is:13
server receive order:QUERY TIME ORDER;the counter is:14
server receive order:QUERY TIME ORDER;the counter is:15
server receive order:QUERY TIME ORDER;the counter is:16
server receive order:QUERY TIME ORDER;the counter is:17
server receive order:QUERY TIME ORDER;the counter is:18
server receive order:QUERY TIME ORDER;the counter is:19
server receive order:QUERY TIME ORDER;the counter is:20
server receive order:QUERY TIME ORDER;the counter is:21
server receive order:QUERY TIME ORDER;the counter is:22
server receive order:QUERY TIME ORDER;the counter is:23
server receive order:QUERY TIME ORDER;the counter is:24
server receive order:QUERY TIME ORDER;the counter is:25
server receive order:QUERY TIME ORDER;the counter is:26
server receive order:QUERY TIME ORDER;the counter is:27
server receive order:QUERY TIME ORDER;the counter is:28
server receive order:QUERY TIME ORDER;the counter is:29
server receive order:QUERY TIME ORDER;the counter is:30
server receive order:QUERY TIME ORDER;the counter is:31
server receive order:QUERY TIME ORDER;the counter is:32
server receive order:QUERY TIME ORDER;the counter is:33
server receive order:QUERY TIME ORDER;the counter is:34
server receive order:QUERY TIME ORDER;the counter is:35
server receive order:QUERY TIME ORDER;the counter is:36
server receive order:QUERY TIME ORDER;the counter is:37
server receive order:QUERY TIME ORDER;the counter is:38
server receive order:QUERY TIME ORDER;the counter is:39
server receive order:QUERY TIME ORDER;the counter is:40
server receive order:QUERY TIME ORDER;the counter is:41
server receive order:QUERY TIME ORDER;the counter is:42
server receive order:QUERY TIME ORDER;the counter is:43
server receive order:QUERY TIME ORDER;the counter is:44
server receive order:QUERY TIME ORDER;the counter is:45
server receive order:QUERY TIME ORDER;the counter is:46
server receive order:QUERY TIME ORDER;the counter is:47
server receive order:QUERY TIME ORDER;the counter is:48
server receive order:QUERY TIME ORDER;the counter is:49
server receive order:QUERY TIME ORDER;the counter is:50
server receive order:QUERY TIME ORDER;the counter is:51
server receive order:QUERY TIME ORDER;the counter is:52
server receive order:QUERY TIME ORDER;the counter is:53
server receive order:QUERY TIME ORDER;the counter is:54
server receive order:QUERY TIME ORDER;the counter is:55
server receive order:QUERY TIME ORDER;the counter is:56
server receive order:QUERY TIME ORDER;the counter is:57
server receive order:QUERY TIME ORDER;the counter is:58
server receive order:QUERY TIME ORDER;the counter is:59
server receive order:QUERY TIME ORDER;the counter is:60
server receive order:QUERY TIME ORDER;the counter is:61
server receive order:QUERY TIME ORDER;the counter is:62
server receive order:QUERY TIME ORDER;the counter is:63
server receive order:QUERY TIME ORDER;the counter is:64
server receive order:QUERY TIME ORDER;the counter is:65
server receive order:QUERY TIME ORDER;the counter is:66
server receive order:QUERY TIME ORDER;the counter is:67
server receive order:QUERY TIME ORDER;the counter is:68
server receive order:QUERY TIME ORDER;the counter is:69
server receive order:QUERY TIME ORDER;the counter is:70
server receive order:QUERY TIME ORDER;the counter is:71
server receive order:QUERY TIME ORDER;the counter is:72
server receive order:QUERY TIME ORDER;the counter is:73
server receive order:QUERY TIME ORDER;the counter is:74
server receive order:QUERY TIME ORDER;the counter is:75
server receive order:QUERY TIME ORDER;the counter is:76
server receive order:QUERY TIME ORDER;the counter is:77
server receive order:QUERY TIME ORDER;the counter is:78
server receive order:QUERY TIME ORDER;the counter is:79
server receive order:QUERY TIME ORDER;the counter is:80
server receive order:QUERY TIME ORDER;the counter is:81
server receive order:QUERY TIME ORDER;the counter is:82
server receive order:QUERY TIME ORDER;the counter is:83
server receive order:QUERY TIME ORDER;the counter is:84
server receive order:QUERY TIME ORDER;the counter is:85
server receive order:QUERY TIME ORDER;the counter is:86
server receive order:QUERY TIME ORDER;the counter is:87
server receive order:QUERY TIME ORDER;the counter is:88
server receive order:QUERY TIME ORDER;the counter is:89
server receive order:QUERY TIME ORDER;the counter is:90
server receive order:QUERY TIME ORDER;the counter is:91
server receive order:QUERY TIME ORDER;the counter is:92
server receive order:QUERY TIME ORDER;the counter is:93
server receive order:QUERY TIME ORDER;the counter is:94
server receive order:QUERY TIME ORDER;the counter is:95
server receive order:QUERY TIME ORDER;the counter is:96
server receive order:QUERY TIME ORDER;the counter is:97
server receive order:QUERY TIME ORDER;the counter is:98
server receive order:QUERY TIME ORDER;the counter is:99
server receive order:QUERY TIME ORDER;the counter is:100

客户端输出

Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :1
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :2
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :3
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :4
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :5
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :6
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :7
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :8
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :9
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :10
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :11
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :12
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :13
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :14
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :15
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :16
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :17
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :18
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :19
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :20
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :21
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :22
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :23
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :24
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :25
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :26
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :27
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :28
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :29
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :30
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :31
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :32
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :33
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :34
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :35
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :36
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :37
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :38
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :39
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :40
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :41
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :42
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :43
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :44
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :45
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :46
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :47
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :48
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :49
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :50
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :51
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :52
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :53
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :54
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :55
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :56
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :57
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :58
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :59
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :60
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :61
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :62
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :63
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :64
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :65
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :66
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :67
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :68
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :69
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :70
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :71
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :72
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :73
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :74
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :75
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :76
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :77
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :78
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :79
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :80
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :81
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :82
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :83
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :84
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :85
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :86
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :87
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :88
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :89
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :90
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :91
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :92
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :93
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :94
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :95
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :96
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :97
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :98
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :99
Now is : Fri Sep 01 19:48:07 CST 2017 ; the counter is :100

如此看来直接使用netty自带的解码器可以完美解决粘包问题,当然拆包问题也是使用这两个解码器就可以搞定了。非常的方便。


csdn code 路径


这个项目的源代码放置在csdn code上,欢迎访问。
netty_study

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

netty之分隔符和定长解码器解决之道

上节我们讲解了LineBasedFrameDecoder和StringDecoder的使用,如果大家理解了这二个东西,那么这一章学起来将是轻车熟路。话不多说开始吧...

Cocos2d-x利用jni调用java层代码

jni的意思是java本地调用,通过jni可以实现java层代码和其他语言写得代码进行交互。在cocos2d-x中,如果想要在c++层调用java层的代码,就是通过jni技术。通过调用java层的代码...

12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用

出处:http://blog.csdn.net/han_xiaoyang/article/details/12163251。 声明:版权所有,转载请注明出处,谢谢。 0、前言      ...

Netty权威指南 第2版学习笔记4——TCP粘包/拆包问题的解决之道

TCP粘包/拆包假设客户端分别发送了两个数据包D1 和D2给服务商厦 ,由于服务端一次读取到的字节数是不确定的,故可能存在4种情况: 服务端分两次读取到了两个独立的数据包,分别是D1 和 D2,没有粘...
  • xundh
  • xundh
  • 2017年01月02日 11:41
  • 386

Netty权威指南 第2版学习笔记9——Channel,Unsafe和 AttributeMap

Channel功能说明io.netty.channel.Channel是Netty网络操抽象类,它聚合了一组功能,包括但不限于网络的读、写,客户端发起连接,主动关闭连接,链路关闭,获取通信双方的网络地...
  • xundh
  • xundh
  • 2017年03月06日 10:54
  • 236

Netty权威指南 第2版学习笔记1——Java的I/O演进之路

I/O基础入门Java1.4之前对I/O的支持并不完善。开发人员在开发高性能I/O程序的时候,会面临一些巨大的挑战和困难,主要问题: 没有数据缓冲区,I/O性能存在问题 没有C/C++的Channel...
  • xundh
  • xundh
  • 2016年12月31日 23:36
  • 278

Netty权威指南 第2版学习笔记11——实现WebSocket

WebSocket 入门WebSocket是HTML5开始提供的一种浏览器与服务间进行全双工通信的网络技术,WebSocket通信协议于2011年被IETF定为标准RFC6455,WebSocket ...
  • xundh
  • xundh
  • 2017年03月12日 16:41
  • 349

Netty权威指南 第2版学习笔记2——NIO入门

传统的BIO编程网络编程的基本模型是Client/Server模型,通过三次扬建立连接,如果连接建立成功,双方就可以通过网络套接字进行通信。BIO通信模型图采用BIO通信模型的服务端,通常由一个独立的...
  • xundh
  • xundh
  • 2017年01月01日 00:34
  • 371

Netty权威指南 第2版学习笔记7——MessagePack编解码及LengthFieldBasedFrameDecoder

MessagePack是一个高效的二进制序列化框架,像JSON一样支持不同语言间的数据交换,速度更快,序列化之后的码流更小MessagePack特点 编解码高效,性能高 序列化后的码流小 支持跨语言 ...
  • xundh
  • xundh
  • 2017年01月02日 21:55
  • 1552

Netty权威指南 第2版学习笔记6——常见序列化与反序列化框架

java.io.Serializable 实现了Java的序列化,但有无法跨语言、序列化后的码流太大、序列化性能太低等缺点业界主流的编解码框架Google的protobuf由谷歌开源而来,将数据结构以...
  • xundh
  • xundh
  • 2017年01月02日 15:12
  • 563
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:<netty权威指南>笔记-以回车换行结尾的消息如何处理半包问题
举报原因:
原因补充:

(最多只允许输入30个字)