Netty进阶——粘包与半包(预设长度方式解决粘包问题)
Posted 小志的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty进阶——粘包与半包(预设长度方式解决粘包问题)相关的知识,希望对你有一定的参考价值。
目录
一、预设长度方式解决粘包问题(代码示例)
1.1、预设长度方式解决粘包问题的服务端代码示例
-
在发送消息前,先约定用定长字节表示接下来数据的长度,服务端加入如下代码:
//设置LTC解码器,4个参数分别为 最大长度,长度偏移,长度占用字节,长度调整,剥离字节数 ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 1, 0, 1));
-
服务端完整代码示例
package com.example.nettytest.netty.day5; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioserverSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import lombok.extern.slf4j.Slf4j; /** * @description: 预设长度方式解决粘包 问题服务端示例 * @author: xz */ @Slf4j public class NerrtPresetLengthServer public static void main(String[] args) new NerrtPresetLengthServer().start(); void start() NioEventLoopGroup boss = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); try ServerBootstrap serverBootstrap = new ServerBootstrap() .channel(NioServerSocketChannel.class) //调整 netty 的接受缓冲区(byteBuf) .childOption(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(16,16,16)) .group(boss, worker) .childHandler(new ChannelInitializer<SocketChannel>() @Override protected void initChannel(SocketChannel ch) throws Exception //设置LTC解码器,4个参数分别为 最大长度,长度偏移,长度占用字节,长度调整,剥离字节数 ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 1, 0, 1)); ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ch.pipeline().addLast(new ChannelInboundHandlerAdapter() //会在连接channel建立成功后,触发active事件 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception log.debug("connected>>>>>>>>>>>>>>>> ", ctx.channel()); super.channelActive(ctx); @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception log.debug("disconnect>>>>>>>>>>>>>>>> ", ctx.channel()); super.channelInactive(ctx); ); ); ChannelFuture channelFuture = serverBootstrap.bind(8080); log.debug(">>>>>>>>>>>>>>>> binding...", channelFuture.channel()); channelFuture.sync(); log.debug(">>>>>>>>>>>>>>>> bound...", channelFuture.channel()); channelFuture.channel().closeFuture().sync(); catch (InterruptedException e) log.error("server error", e); finally boss.shutdownGracefully(); worker.shutdownGracefully(); log.debug(">>>>>>>>>>>>>>>>stoped");
1.2、预设长度方式解决粘包问题的客户端代码示例
- 客户端代码示例
package com.example.nettytest.netty.day5;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import java.util.Random;
/**
* @description: 预设长度方式解决粘包 问题客户端示例
* @author: xz
*/
@Slf4j
public class NerrtPresetLengthClient
public static void main(String[] args)
send();
private static void send()
NioEventLoopGroup worker = new NioEventLoopGroup();
try
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(worker);
bootstrap.handler(new ChannelInitializer<SocketChannel>()
@Override
protected void initChannel(SocketChannel ch)
log.debug("connetted...");
ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
ch.pipeline().addLast(new ChannelInboundHandlerAdapter()
// 会在连接 channel 建立成功后,会触发 active 事件
@Override
public void channelActive(ChannelHandlerContext ctx)
log.debug("sending...");
ByteBuf buf = ctx.alloc().buffer();
char c = 'a';
Random r = new Random();
for (int i = 0; i < 10; i++)
byte length = (byte) (r.nextInt(16) + 1);
// 先写入长度
buf.writeByte(length);
// 再写入数据
for (int j = 1; j <= length; j++)
buf.writeByte((byte) c);
c++;
ctx.writeAndFlush(buf);
);
);
ChannelFuture channelFuture = bootstrap.connect("localhost", 8080).sync();
channelFuture.channel().closeFuture().sync();
catch (InterruptedException e)
log.error("client error", e);
finally
worker.shutdownGracefully();
1.3、分别启动服务端,客户端,查看服务端结果输出
- 先启动服务端
- 再启动客户端,输入日志如下:
- 再次查看服务端,日志如下:
以上是关于Netty进阶——粘包与半包(预设长度方式解决粘包问题)的主要内容,如果未能解决你的问题,请参考以下文章