如何解决netty拆包问题

近期做物联网使用到了netty,遇到了不少问题,一种问题是粘包,另一种是拆包,虽然相对于我的项目不是什么大的问题,但是如果要对于有些项目数据可靠性来说这可是大的问题。

顺便提一下我的项目中的需求,我做的是智能大棚项目,dtu每隔一段时间会把轮询中的感应器数据,比如温度、湿度、ph值传给服务器。前期我设计每半分钟传送数据一次,看报得太密没有必要,就两分钟一次数据传送,dtu传送时除非程序dubug时断点或网络阻塞才会出现粘包现象,由于本身接收到的moudbu数据很少,出现过拆包现象的少,即便我不考虑粘包和拆包问题也没有关系。但做为程序员的我们要把尽可能考虑的问题都考虑到,把能用的数据尽可能都用到,这就不得不考虑了,粘包问题好解决,只要按其协议截取bytes字节数据就可以了——传感器说明书中有的,多种传感器要根据收集到数据地址区分就可以了。但是拆包问题就不是一个好解决的事了,我偿试过网上那种在编码器中解决的方案,一般都是看解码器中数够不够长度,够了读取后交给转码下面操作,这种方式不适合我的需求:

1、数据不是定长数据;

2、想根据地址位动态获取数据长度,要使用到spring注入其他数据便于查询,没有找到解码器能被sping管理的方法。

但查询了国内很多网站,都是用的此方法,大部分都是定长或者字段中就有字节长度。没有办法只有放弃了。近几天与chatGPT会话谈论时,发现了它给的不少问题让我眼前一亮,就试着问了它这个问题,他给我的回答让我眼前一亮,直接上代码吧:

public class NettyServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         public void initChannel(SocketChannel ch) throws Exception {
                             ch.pipeline().addLast(new StringDecoder());
                             ch.pipeline().addLast(new StringEncoder());
                             ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                                 private StringBuilder messageBuilder = new StringBuilder();


                                 @Override
                                 protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                     messageBuilder.append(msg);
                                     if (msg.endsWith("!")) {
                                         String message = messageBuilder.toString();
                                         messageBuilder = new StringBuilder();
                                         System.out.println("Received message: " + message);
                                     }
                                 }
                             });
                         }
                     });


            ChannelFuture future = bootstrap.bind(8888).sync();
            System.out.println("Server started on port 8888");


            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

我们可以考虑使用StringBuilder来缓存读到的数据,在Handler中可以依赖注入其它类非常方便,截取bytes到查询到的长度后,剩余的再重新new StringBuilder,并放进去作为开头就可以了,由于StringBuilder写在每个childHandler类中,不必考虑线程安全问题,同时写在读取方法read外部,上一次未截取完的信息下一次接着还可以使用,这样粘包和拆包问题都解决了。

希望这个思路能帮助大家!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值