Netty源码(三):Netty的粘包问题ByteToMessageDecoder

1. 产生粘包和半包的原因

粘包产生的原因:两个包小于缓存区的大小,传送数据会将两个包都放在缓冲区中一起发送,就会产生粘包的问题。
半包产生的原因:当某一个包的大于缓冲区的大小,会被发送多次,每次就收到的就是一个不完整的数据包。

常见的处理手段:
在这里插入图片描述

netty对不同粘包半包问题的支持类
在这里插入图片描述

2. 问题一:Netty如何实现编码解码的

查看ByteToMessageDecoder,该类是解码器的实现类,查看其中的channelRead方法
1.调用了cumulator.cumulate()方法来实现数据包的拼接的操作
2.callDecode()方法解析数据包
在这里插入图片描述

2.1 cumulator.cumulate()方法拼接数据包

跟进源码,发现他分为两步:
1.如果是第一个数据包,就直接返回该数据包
2.如果不是第一个数据包,就将最新的数据追加导员来已经接收的数据包内
在这里插入图片描述

2.2 callDecode()方法解析数据包

核心实现方法,decodeRemovalReentryProtection就是callDecode中的核心步骤
在这里插入图片描述
跟进源码decodeRemovalReentryProtection的源码,其中核心方法是514行的decode方法,但是此方法是一个抽象方法,也就是说ByteToMessageDecoder只是一个模板类,具体的decode方法实现在子类中
decodeRemovalReentryProtection
于是我们查看ByteToMessageDecoder的一个子类FixedLengthFrameDecoderFixedLengthFrameDecoder是固定长度的编码解码方式,如果数据不足会补充空格等数据,它的decode方法如下:
1.如果我们接受到的数据小于数据帧限制的长度,那么无法解析数据,直接返回null
2.否则调用readRetainedSlice方法进行解析,readRetainedSlice就是将ByteBuf切出frameLength长度的数据出来
在这里插入图片描述
总结:Netty提供了一个ByteToMessageDecoder模板类,数据包的拼接交给该类完成,但是数据包的解析decode是一个抽象方法,具体实现交给子类完成。

3.问题二:LengthFieldBasedFrameDecoder编码器的实现

核心就是其中的四个参数:
1.lengthFieldOffset // length字段的偏移量
2.lengthFieldLength // legnth字段所占的长度
3.lengthAdjustment // 可能我们除了实际内容字段以外,还额外增加2个字段的其他信息,lengthAdjustment=2,那么需要读取的数据就是length+2
4.initialBytesToStrip // 我们解析出来的数据是从第几位开始的,如果我们不需要接收length字段,那么initialBytesToStrip=2,解析出来就只有内容部分
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,使用Netty接收数据并转发数据可以通过以下步骤完成: 1. 首先,我们需要在Spring Boot项目中引入Netty的依赖。可以通过在pom.xml文件中添加以下代码来实现: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.32.Final</version> </dependency> ``` 2. 接下来,我们需要创建一个Netty服务器来接收数据。可以创建一个新的类来实现服务器的启动和配置。例如,我们可以创建一个名为NettyServer的类: ```java @Component public class NettyServer { private final int port = 8080; // 启动Netty服务器 @PostConstruct public void startServer() { EventLoopGroup bossGroup = new NioEventLoopGroup(); // 接收进来的连接 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 处理已接收连接的流量 try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 使用NIO传输 .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast(new NettyServerHandler()); // 处理网络IO事件 } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.bind(port).sync(); // 绑定端口,开始接收进来的连接 future.channel().closeFuture().sync(); // 关闭服务器通道 } catch (Exception e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ``` 3. 然后,我们需要创建一个Netty服务器处理程序来处理接收到的数据并进行相应的转发操作。例如,我们可以创建一个名为NettyServerHandler的类: ```java public class NettyServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 接收到数据后的处理逻辑 // 在这里可以根据实际需求进行数据转发操作或其他处理 // 示例:将接收到的数据转发给其他服务器 String data = (String) msg; String forwardedData = forwardData(data); ctx.writeAndFlush(forwardedData); } private String forwardData(String data) { // 实现数据转发的逻辑 // 可以使用其他网络客户端或第方API进行转发操作 return "Forwarded data: " + data; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } ``` 4. 最后,我们可以编写用于接收和处理Netty服务器返回结果的代码。可以在Spring Boot中的任何组件中使用Netty的客户端来处理转发后的数据。例如,我们可以在控制器中编写以下代码: ```java @RestController public class NettyClientController { @GetMapping("/forwardData") public String forwardData() { // 创建Netty客户端并发送数据到服务器 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 接收服务器返回的转发后数据 String forwardedData = (String) msg; // 处理转发后的数据 } }); } }); ChannelFuture future = bootstrap.connect("localhost", 8080).sync(); // 连接到服务器 future.channel().writeAndFlush("Data to be forwarded"); // 发送需要转发的数据 future.channel().closeFuture().sync(); // 关闭客户端通道 } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } return "Data forwarded successfully"; } } ``` 通过以上步骤,我们可以在Spring Boot中使用Netty接收数据并进行转发操作。根据实际需求,可以在Netty服务器处理程序中添加更多的逻辑来实现更复杂的数据转发操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值