Netty Custom DelimiterBasedFrameDecoder

时间:2014-05-07 21:31:12

标签: java netty

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

这一个供应商消息包含HEADER,BODY和TRAILER。 标头是1个字节,是STX(0x02) 身体长度可变 预告片是2个字节,包含一个ETX(0x03),后跟一个LRC。

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

STX   BODY   ETX  LRC
02  37000000 06   18

我们最初使用DelimiterBasedFrameDecoder将ETX定义为分隔符,但是当我们这样做时,我们松开了作为消息一部分的LRC字节。结果,LRC最终成为我们解码的下一条消息的第一个字节。有没有办法使用DelimiterBasedFrameDecoder并读取一个字节超过ETX分隔符?

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

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

我对此有任何帮助表示赞赏!

由于 添

更新

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

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 个答案:

答案 0 :(得分:1)

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