Tcp粘包拆包解决之道
原因:为什么会粘包,为什么需要拆包?
Tcp是个“流”协议,并没有指定的分界线,一个包,可能会被Tcp拆分成多个包发送,也可能将多个小包,封装成一个
大的数据包发送
首先,据计算机网络中概述
- Tcp提供全双工通信,在Tcp的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据,发送时,应用程序把数据发送给发送缓冲区,应用程序发送工作完成,接收时,Tcp将接收到的数据放入接收缓冲区,应用程序到合适的时候读取
- Tcp的数据流,是一串字节序列,虽然和应用程序的交互,是一次一个数据块,但是Tcp将交互的数据,看做是一串无结构的字节流。Tcp不保证接收方应用程序所收到的数据块和发送方的数据块具有对应大小的关系(例如:发送方应用程序交给发送方的Tcp共10个数据块,但是接收方的Tcp可能仅用了4个数据块就把接收到的字节流交付给上层的应用程序,也就是说,你寄了10个快递给老A,但是10个快递被物流公司用4个纸盒给你装起来了,老A收到的就是4个纸盒)。所以,老A需要将4个快递盒全部拆分,还原成10个快递,才是你发给老A的东西
- 在Tcp的通信过程中,都是面临者缓冲区进行数据的IO,所以,如果应用程序发送的数据过大,将缓冲区比喻为一个大号快递盒,那么就需要将应用程序发送的数据包进行部分拆分,然后发送出去(当然和快递有区分,有的快递拆不了,但是应用程序发送的所有数据,是都转成了字节序列的),这就是Tcp拆包
- Tcp的通信,虽然是以字节序列进行传输,但是Tcp的数据单元却是报文段,一个Tcp的报文段分为首部和数据两部分,而且,Tcp的报文段,是有最大长度的,成为MSS,它是指数据部分的最大长度,所以,当进行了MSS大小的分段时,一刀切下去,原有的数据就肯定不在一个数据段内了
- 假如,应用程序连续发送了两个数据包,但是这个两个数据包加在一起既没有超过缓冲区大小,又不超过一个Tcp段的大小,那么,这两个数据包就发生了Tcp粘包
- 在TCP通讯协议中TCP的每个包头的长度都是固定的,总长度不能超过MTU(最大传输单元),且数据长度不能超过MSS(MSS=MTU-20bytes(IP包头)-20bytes(TCP包头))。如果超过了MTU系统会进行拆包处理。
常见的解决策略
- 消息定长,例如每个报文的大小为固定长度的200字节,如果不够,空位补空格
- 在包尾增加回车换行符进行分割,例如FTP协议
- 将消息分为消息头和消息体,消息头中包含消息总长度的字段,通常设计思路为消息头的第一个字段使用int32来表示消息的总长度
- 更复杂的应用层协议
未考虑Tcp粘包导致功能异常的样例
服务端代码
package com.su.netty;
import com.su.bio.BioTest;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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;
/**
* @ClassName:NettyTimeServer
* @Author: sz
* @Date: 2022/8/23 17:37
* @Description:
*/
public class NettyTimeServer {
public static void main(String[] args) throws Exception {
int port = 8080;
if(args !=null && args.length>0){
try {
port = Integer.parseInt(args[0]);
}catch (Exception e){
}
}
new NettyTimeServer().bind(port);
}
public void bind(int port) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChildChannelHandler());
//绑定端口 同步等待成功
ChannelFuture f = b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeServerHandler());
}
}
}
服务端Handler代码
package com.su.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* @ClassName:TimeServerHandler
* @Author: sz
* @Date: 2022/8/23 17:55
* @Description:
*/
public class TimeServerHandler extends ChannelInboundHandlerAdapter {
private int counter;
@Override
public void channelRead(ChannelHandlerContext ctx , Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] req = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(req);
String body = new String(req,"UTF-8").substring(0,req.length - System.getProperty("line.separator").length());
System.out.println("The time server receive order :"+body + "; the counter is "+ ++counter);
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
currentTime = currentTime + System.getProperty("line.separator");
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx ){
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx , Throwable cause){
ctx.close();
}
}
客户端代码
package com.su.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @ClassName:NettyTimeClient
* @Author: sz
* @Date: 2022/8/23 18:24
* @Description:
*/
public class NettyTimeClient {
public static void main(String[] args) throws Exception {
int port = 8080;
if(args !=null && args.length>0){
try {
port = Integer.parseInt(args[0]);
}catch (Exception e){
}
}
new NettyTimeClient().connect(port,"127.0.0.1");
}
public void connect(int port ,String host)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
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new TimeClientHandler());
}
});
ChannelFuture f = b.connect(host,port).sync();
f.channel().closeFuture().sync();
}catch (Exception e){
group.shutdownGracefully();
}
}
}
客户端Hanlder
package com.su.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Date;
/**
* @ClassName:TimeClientHandler
* @Author: sz
* @Date: 2022/8/23 18:30
* @Description:
*/
public class TimeClientHandler extends ChannelInboundHandlerAdapter {
private int counter;
private byte[] req ;
public TimeClientHandler(){
req = ("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();
}
@Override
public void channelActive(ChannelHandlerContext ctx){
ByteBuf message = null;
for (int i =0 ;i<100; i++){
message = Unpooled.buffer(req.length);
message.writeBytes(req);
ctx.writeAndFlush(message);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx , Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] req = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(req);
String body = new String(req,"UTF-8");
System.out.println("Now is :"+body+";the counter is :"+ ++counter);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx ){
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx , Throwable cause){
ctx.close();
}
}
运行结果
服务端
The time server receive order :QUERY TIME ORDER; the counter is 1
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 2
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 3
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 4
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 5
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 6
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 7
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 8
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 9
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 10
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 11
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 12
The time server receive order :QUERY TIME ORDER; the counter is 13
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 14
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 15
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 16
The time server receive order :QUERY TIME ORDER; the counter is 17
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 18
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 19
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 20
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 21
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 22
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 23
The time server receive order :QUERY TIME ORDER; the counter is 24
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 25
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 26
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 27
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 28
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 29
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 30
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 31
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 32
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER; the counter is 33
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 34
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 35
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 36
The time server receive order :QUERY TIME ORDER
QUERY TIME ORDER
QUERY TIME ORDER; the counter is 37
客户端:
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
Thu Sep 15 10:48:10 CST 2022
BAD ORDER
BAD ORDER
BAD ORDER
Thu Sep 15 10:48:10 CST 2022
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
Thu Sep 15 10:48:10 CST 2022
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
BAD ORDER
;the counter is :1
结论
服务端的运行结果表明收到了37条消息,但是却包含100条QUERY TIME ORDER,发生了粘包。由于消息不等于QUERY TIME ORDER,所以客户端收到的是Bad Order,但是客户端也只收到了一条消息,说明服务端的应答消息也发生了Tcp粘包
编解码器解决粘包问题
netty提供了多种编解码器处理粘包拆包问题
服务端代码
package com.su.netty;
import com.su.bio.BioTest;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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 io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
* @ClassName:NettyTimeServer
* @Author: sz
* @Date: 2022/8/23 17:37
* @Description:
*/
public class NettyTimeServer {
public static void main(String[] args) throws Exception {
int port = 8080;
if(args !=null && args.length>0){
try {
port = Integer.parseInt(args[0]);
}catch (Exception e){
}
}
new NettyTimeServer().bind(port);
}
public void bind(int port) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChildChannelHandler());
//绑定端口 同步等待成功
ChannelFuture f = b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
socketChannel.pipeline().addLast(new StringDecoder());
socketChannel.pipeline().addLast(new TimeServerHandler());
}
}
}
服务端hanlder
package com.su.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* @ClassName:TimeServerHandler
* @Author: sz
* @Date: 2022/8/23 17:55
* @Description:
*/
public class TimeServerHandler extends ChannelInboundHandlerAdapter {
private int counter;
@Override
public void channelRead(ChannelHandlerContext ctx , Object msg) throws Exception {
String body = (String) msg;
System.out.println("The time server receive order :"+body + "; the counter is "+ ++counter);
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
currentTime = currentTime + System.getProperty("line.separator");
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx ){
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx , Throwable cause){
ctx.close();
}
}
客户端代码
package com.su.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
* @ClassName:NettyTimeClient
* @Author: sz
* @Date: 2022/8/23 18:24
* @Description:
*/
public class NettyTimeClient {
public static void main(String[] args) throws Exception {
int port = 8080;
if(args !=null && args.length>0){
try {
port = Integer.parseInt(args[0]);
}catch (Exception e){
}
}
new NettyTimeClient().connect(port,"127.0.0.1");
}
public void connect(int port ,String host)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
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new LineBasedFrameDecoder(1024));
channel.pipeline().addLast(new StringDecoder());
channel.pipeline().addLast(new TimeClientHandler());
}
});
ChannelFuture f = b.connect(host,port).sync();
f.channel().closeFuture().sync();
}catch (Exception e){
group.shutdownGracefully();
}
}
}
客户端handler
package com.su.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Date;
/**
* @ClassName:TimeClientHandler
* @Author: sz
* @Date: 2022/8/23 18:30
* @Description:
*/
public class TimeClientHandler extends ChannelInboundHandlerAdapter {
private int counter;
private byte[] req ;
public TimeClientHandler(){
req = ("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();
}
@Override
public void channelActive(ChannelHandlerContext ctx){
ByteBuf message = null;
for (int i =0 ;i<100; i++){
message = Unpooled.buffer(req.length);
message.writeBytes(req);
ctx.writeAndFlush(message);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx , Object msg) throws Exception {
String body = (String) msg;
System.out.println("Now is :"+body+";the counter is :"+ ++counter);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx ){
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx , Throwable cause){
ctx.close();
}
}
运行结果
服务端接收
The time server receive order :QUERY TIME ORDER; the counter is 1
The time server receive order :QUERY TIME ORDER; the counter is 2
The time server receive order :QUERY TIME ORDER; the counter is 3
The time server receive order :QUERY TIME ORDER; the counter is 4
The time server receive order :QUERY TIME ORDER; the counter is 5
The time server receive order :QUERY TIME ORDER; the counter is 6
The time server receive order :QUERY TIME ORDER; the counter is 7
The time server receive order :QUERY TIME ORDER; the counter is 8
The time server receive order :QUERY TIME ORDER; the counter is 9
The time server receive order :QUERY TIME ORDER; the counter is 10
The time server receive order :QUERY TIME ORDER; the counter is 11
The time server receive order :QUERY TIME ORDER; the counter is 12
The time server receive order :QUERY TIME ORDER; the counter is 13
The time server receive order :QUERY TIME ORDER; the counter is 14
The time server receive order :QUERY TIME ORDER; the counter is 15
The time server receive order :QUERY TIME ORDER; the counter is 16
The time server receive order :QUERY TIME ORDER; the counter is 17
The time server receive order :QUERY TIME ORDER; the counter is 18
The time server receive order :QUERY TIME ORDER; the counter is 19
The time server receive order :QUERY TIME ORDER; the counter is 20
The time server receive order :QUERY TIME ORDER; the counter is 21
The time server receive order :QUERY TIME ORDER; the counter is 22
The time server receive order :QUERY TIME ORDER; the counter is 23
The time server receive order :QUERY TIME ORDER; the counter is 24
The time server receive order :QUERY TIME ORDER; the counter is 25
The time server receive order :QUERY TIME ORDER; the counter is 26
The time server receive order :QUERY TIME ORDER; the counter is 27
The time server receive order :QUERY TIME ORDER; the counter is 28
The time server receive order :QUERY TIME ORDER; the counter is 29
The time server receive order :QUERY TIME ORDER; the counter is 30
The time server receive order :QUERY TIME ORDER; the counter is 31
The time server receive order :QUERY TIME ORDER; the counter is 32
The time server receive order :QUERY TIME ORDER; the counter is 33
The time server receive order :QUERY TIME ORDER; the counter is 34
The time server receive order :QUERY TIME ORDER; the counter is 35
The time server receive order :QUERY TIME ORDER; the counter is 36
The time server receive order :QUERY TIME ORDER; the counter is 37
The time server receive order :QUERY TIME ORDER; the counter is 38
The time server receive order :QUERY TIME ORDER; the counter is 39
The time server receive order :QUERY TIME ORDER; the counter is 40
The time server receive order :QUERY TIME ORDER; the counter is 41
The time server receive order :QUERY TIME ORDER; the counter is 42
The time server receive order :QUERY TIME ORDER; the counter is 43
The time server receive order :QUERY TIME ORDER; the counter is 44
The time server receive order :QUERY TIME ORDER; the counter is 45
The time server receive order :QUERY TIME ORDER; the counter is 46
The time server receive order :QUERY TIME ORDER; the counter is 47
The time server receive order :QUERY TIME ORDER; the counter is 48
The time server receive order :QUERY TIME ORDER; the counter is 49
The time server receive order :QUERY TIME ORDER; the counter is 50
The time server receive order :QUERY TIME ORDER; the counter is 51
The time server receive order :QUERY TIME ORDER; the counter is 52
The time server receive order :QUERY TIME ORDER; the counter is 53
The time server receive order :QUERY TIME ORDER; the counter is 54
The time server receive order :QUERY TIME ORDER; the counter is 55
The time server receive order :QUERY TIME ORDER; the counter is 56
The time server receive order :QUERY TIME ORDER; the counter is 57
The time server receive order :QUERY TIME ORDER; the counter is 58
The time server receive order :QUERY TIME ORDER; the counter is 59
The time server receive order :QUERY TIME ORDER; the counter is 60
The time server receive order :QUERY TIME ORDER; the counter is 61
The time server receive order :QUERY TIME ORDER; the counter is 62
The time server receive order :QUERY TIME ORDER; the counter is 63
The time server receive order :QUERY TIME ORDER; the counter is 64
The time server receive order :QUERY TIME ORDER; the counter is 65
The time server receive order :QUERY TIME ORDER; the counter is 66
The time server receive order :QUERY TIME ORDER; the counter is 67
The time server receive order :QUERY TIME ORDER; the counter is 68
The time server receive order :QUERY TIME ORDER; the counter is 69
The time server receive order :QUERY TIME ORDER; the counter is 70
The time server receive order :QUERY TIME ORDER; the counter is 71
The time server receive order :QUERY TIME ORDER; the counter is 72
The time server receive order :QUERY TIME ORDER; the counter is 73
The time server receive order :QUERY TIME ORDER; the counter is 74
The time server receive order :QUERY TIME ORDER; the counter is 75
The time server receive order :QUERY TIME ORDER; the counter is 76
The time server receive order :QUERY TIME ORDER; the counter is 77
The time server receive order :QUERY TIME ORDER; the counter is 78
The time server receive order :QUERY TIME ORDER; the counter is 79
The time server receive order :QUERY TIME ORDER; the counter is 80
The time server receive order :QUERY TIME ORDER; the counter is 81
The time server receive order :QUERY TIME ORDER; the counter is 82
The time server receive order :QUERY TIME ORDER; the counter is 83
The time server receive order :QUERY TIME ORDER; the counter is 84
The time server receive order :QUERY TIME ORDER; the counter is 85
The time server receive order :QUERY TIME ORDER; the counter is 86
The time server receive order :QUERY TIME ORDER; the counter is 87
The time server receive order :QUERY TIME ORDER; the counter is 88
The time server receive order :QUERY TIME ORDER; the counter is 89
The time server receive order :QUERY TIME ORDER; the counter is 90
The time server receive order :QUERY TIME ORDER; the counter is 91
The time server receive order :QUERY TIME ORDER; the counter is 92
The time server receive order :QUERY TIME ORDER; the counter is 93
The time server receive order :QUERY TIME ORDER; the counter is 94
The time server receive order :QUERY TIME ORDER; the counter is 95
The time server receive order :QUERY TIME ORDER; the counter is 96
The time server receive order :QUERY TIME ORDER; the counter is 97
The time server receive order :QUERY TIME ORDER; the counter is 98
The time server receive order :QUERY TIME ORDER; the counter is 99
The time server receive order :QUERY TIME ORDER; the counter is 100
客户端接收
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :1
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :2
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :3
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :4
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :5
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :6
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :7
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :8
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :9
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :10
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :11
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :12
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :13
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :14
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :15
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :16
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :17
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :18
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :19
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :20
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :21
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :22
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :23
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :24
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :25
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :26
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :27
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :28
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :29
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :30
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :31
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :32
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :33
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :34
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :35
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :36
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :37
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :38
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :39
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :40
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :41
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :42
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :43
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :44
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :45
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :46
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :47
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :48
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :49
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :50
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :51
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :52
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :53
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :54
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :55
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :56
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :57
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :58
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :59
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :60
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :61
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :62
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :63
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :64
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :65
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :66
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :67
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :68
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :69
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :70
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :71
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :72
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :73
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :74
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :75
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :76
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :77
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :78
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :79
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :80
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :81
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :82
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :83
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :84
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :85
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :86
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :87
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :88
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :89
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :90
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :91
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :92
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :93
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :94
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :95
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :96
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :97
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :98
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :99
Now is :Thu Sep 15 11:01:08 CST 2022;the counter is :100
结论
netty提供的LineBasedFrameDecoder,依次遍历ByteBuf中的可读字节,判断看是否有“\n”或者“\r\n”,如果有就以此位置为结束位置,从可读位置到结束位置组成一行。它是以换行符为结束标识的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度,如果连续读取到最大长度后仍没有发现换行符,就回抛出异常,同时忽略之前读到的异常码流
StringDecoder的功能 很简单,就是将接收到的对象转换成字符串,然后继续调用后面的handler,LineBasedFrameDecoder+StringDecoder组合就是按行切换的文本解码器,它被设计用来支持Tcp的粘包和拆包
|