当前位置: 首页 > 知识库问答 >
问题:

Netty自定义DelimiterBasedFrameDecoder

邹山
2023-03-14

我的公司正在探索使用Netty框架实现消息路由器的可能性。它将要路由的消息来自许多不同的来源,并且都有自己的格式。在大多数情况下,消息都是XML格式的,其中包含一个包含正文长度的头。然而,我们有一个供应商谁的消息是不同的,不包含长度的身体。

这一个供应商的消息包含一个标题、正文和尾部。报头为1字节,是一个STX(0x02),正文为可变长度,尾部为2字节,包含一个ETX(0x03),后跟一个LRC。

因此典型的消息可能如下所示:

STX   BODY   ETX  LRC
02  37000000 06   18

我们最初使用DelimiterBasedFrameDecoder将ETX定义为分隔符,但是当我们这样做时,我们丢失了作为消息一部分的LRC字节。因此,LRC最终成为我们解码的下一个消息的第一个字节。是否有一种方法可以使用DelimiterBasedFrameDecoder并读取超过ETX分隔符的一个字节?

此外,当我们向源发送响应时,源将向我们发送一个ACK,而我们也必须用ACK来响应该ACK。

我认为我们需要一个自定义的解码器来读取字节,如果它是一个ACK,那么它就会通知下一个处理程序,否则,它就会继续读取,直到通过ETX读取1个字节,然后将该消息发送到下一个处理程序。这看起来合理吗?是否有更好的方法,或者Netty中是否有一个解码器,我可能想要使用它来代替DelimiterBasedFrameDecoder?

我能得到的任何帮助都很感激!

所以在诺曼的建议下,我创建了以下解码器:

public class MyDecoder extends DelimiterBasedFrameDecoder{

    public MyDecoder(int maxFrameLength, boolean stripDelimiter, ByteBuf delimiter) {
        super(maxFrameLength, stripDelimiter, delimiter);
        this.setSingleDecode(true);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
        Object frame = super.decode(ctx, buffer);
        ByteBuf bufFrame = null;
    
    if(frame instanceof ByteBuf){
        bufFrame = (ByteBuf)frame;
        
        }else{
            System.out.println("OBJECT TYPE: " + frame.getClass().getSimpleName());
        }
    
        byte lrc = buffer.readByte();
        bufFrame.writeByte(lrc);
        return bufFrame;
   }

    public MyDecoder(int maxFrameLength, ByteBuf delimiter) {
        super(maxFrameLength, delimiter);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        System.out.println("VERIFONE DECODER READY");
    }
}

我的处理程序是用以下内容初始化的...

public class MyChannelInitializer extends ChannelInitializer<SocketChannel> {

    ByteBuf delimiter;
    byte[] ETX = {0x03};
    byte[] STX = {0x02};

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        setupDelimiter();
        ch.pipeline().addLast(new MyDecoder(65*1024, false, delimiter));
        ch.pipeline().addLast(new ByteArrayDecoder());
        ch.pipeline().addLast(new ByteArrayEncoder());
        ch.pipeline().addLast(new MyHandler());
   }

   private void setupDelimiter(){
       delimiter = Unpooled.copiedBuffer(ETX);
    
   }

}

所有的工作都是预期的,我得到了我的完整消息,包括LRC,它是ETX之后的1个字节,然而,它抛出了以下异常...

May 09, 2014 5:11:43 PM io.netty.channel.DefaultChannelPipeline$TailHandler exceptionCaught
WARNING: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It
usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: java.lang.NullPointerException
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:258)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:140)
at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:74)
at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:138)
at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:320)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:127)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:452)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:794)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at com.test.MyDecoder.decode(MyDecoder.java:33)
at     io.netty.handler.codec.DelimiterBasedFrameDecoder.decode(DelimiterBasedFrameDecoder.java:216)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:227)
... 11 more

我不知道为什么会这样...

对我该看什么有什么想法吗?

共有1个答案

尹冠宇
2023-03-14

您将需要自己版本的DelimiterBasedFrameDecoder来处理该案例。基本上只是Netty附带的一个副本,但在分隔符之后还要多消耗1个字节。

 类似资料:
  • 感谢SpanInjector和SpanExtractor,您可以自定义spans的创建和传播方式。 目前有两种在进程之间传递跟踪信息的内置方式: 通过Spring Integration 通过HTTP Span ids从Zipkin兼容(B3)头(Message或HTTP头)中提取,以启动或加入现有跟踪。跟踪信息被注入到任何出站请求中,所以下一跳可以提取它们。 与以前版本的Sleuth相比,重要的

  • whistle提供了插件的方式扩展协议,具体参考:插件开发

  • 我目前正在努力实现一种保护隐私的数据挖掘算法。对于不同各方之间的通信部分,我使用的是Netty 4.0。双方之间的通信流如下所示: 其中是启动和控制整个计算的主方。安全多方乘法的逻辑位于 Netty 中。还有另一种用于安全添加的协议。 目前,我使用类似的解决方案,如Netty核心团队的Norman Maurer所示,以了解子协议计算是否已完成。但这感觉有点像是在对抗框架。 是否有办法从< code

  • 问题内容: 美好的一天。 如果可以根据需要更改JLabel和JTextField字体大小,是否还可以更改JTable的列名和元素的字体样式(大小,外观,颜色)? 另外,我正在使用Windows的外观。 谢谢, 问题答案: 有默认值,以及和。您可以使用与键来覆盖默认。

  • 问题内容: 美好的一天。 如果可以根据需要更改JLabel和JTextField字体大小,是否还可以更改JTable的列名和元素的字体样式(大小,外观,颜色)? 另外,我正在使用Windows的外观。 谢谢, 问题答案: 有默认值,以及和。您可以使用与键来覆盖默认。

  • 问题内容: 我正在尝试在发送XHR之前先听它们。该方法类似于jQuery的beforeSend。 我的目标是在发送所有XHR之前监听它们。我想最接近的事情是检查上面是否? 上面的代码是否会因为我使用原型而导致诸如jQuery之类的ajax库出现故障? 问题答案: 我正在尝试在发送XHR之前先听它们。 然后尝试欺骗该方法,而不是一种。 上面的代码是否会因为我在XMLHttpRequest上使用原型而