LineBasedFrameDecoder 的继承关系图
使用LineBasedFrameDecoder解决粘包问题
Server端
在Client端发送字符串"1234567890"到服务端,并在客户端、服务端都增加一个计数器,记录两边请求与回应的次数。
服务端加入 LineBasedFrameDecoder 与 StringDecoder。
StringDecoder 将 ByteBuf 解码成字符串对象。
@Component
public class Test2Server {
private final EventLoopGroup boss = new NioEventLoopGroup();
private final EventLoopGroup worker = new NioEventLoopGroup();
private static final Logger logger = LoggerFactory.getLogger(Test2Server.class);
public void startup(){
try {
ServerBootstrap server = new ServerBootstrap();
server.group(boss, worker)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(new LineBasedFrameDecoder(1024));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new TimeServerHandler());
}
});
ChannelFuture cf = server.bind(9092).sync();
logger.info("server start");
cf.channel().closeFuture().sync();
}
catch(Exception e){
e.printStackTrace();
}finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
Test2ServerHandler.java
使用String字符串接收
public class Test2ServerHandler extends SimpleChannelInboundHandler<Object>
{
private int counter;
private final Logger logger = LoggerFactory.getLogger(Test2ServerHandler.class);
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
//msg 已经是解码后的消息,直接转为 string 字符串
String body = (String)msg;
logger.info("Server got msg:" + body + ", the count is:" + ++counter);
}
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
//
}
}
Client端
在Client端也增加一个计数器,记录从服务端收到的响应次数。
public class Test2Client {
private static Logger logger = LoggerFactory.getLogger(Test2Client.class);
//
public static void main(String[] args){
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap client = new Bootstrap();
client.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception{
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
logger.info("client start");
ChannelFuture f = client.connect("127.0.0.1",9092).sync();
f.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
}
}
Test2ClientHandler.java
public class TimeClientHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = LoggerFactory.getLogger(TimeClientHandler.class);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
byte[] by = "1234567890\r\n123".getBytes();
ByteBuf buf = Unpooled.buffer(by.length);
buf.writeBytes(by);
ctx.writeAndFlush(buf);
byte[] by2 = "4567890\r\n4444444\n".getBytes();
ByteBuf buf2 = Unpooled.buffer(by2.length);
buf2.writeBytes(by2);
ctx.writeAndFlush(buf2);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
//
}
}
结果
数据"1234567890"进行了正确分割,两边counter计数器等于3,表明服务端收到了3次请求。
日志
2022-02-21 16:24:31.632 INFO 11676 --- [ntLoopGroup-3-1] cn.wxt.test.test2.Test2ServerHandler : Server got msg:1234567890, the counter is:1
2022-02-21 16:24:31.632 INFO 11676 --- [ntLoopGroup-3-1] cn.wxt.test.test2.Test2ServerHandler : Server got msg:1234567890, the counter is:2
2022-02-21 16:24:31.632 INFO 11676 --- [ntLoopGroup-3-1] cn.wxt.test.test2.Test2ServerHandler : Server got msg:4444444, the counter is:3
更改前
更改前 counter等于1,表明服务端实际上只收到了1条请求,很显然这里发生了粘包,即客户端的多个包合成了一个发送到了服务端
2022-02-21 16:43:55.758 INFO 1156 --- [ntLoopGroup-3-1] cn.wxt.test.test2.Test2ServerHandler : Server got msg:1234567890
1234567890
4444444
, the counter is:1
参考
end