问题描述
我的公司正在探索使用Netty Framework实施消息路由器的可能性.将要路由的消息来自许多不同的来源,并且都有各自的格式.在大多数情况下,消息采用XML格式,其中包含包含正文长度的标头.但是,我们有一个供应商,其信息是不同的,并且不包含正文的长度.
My company is exploring the possibility of using the Netty Framework to implement a message router. The messages that it will be routing come from many different sources and all have their own formats. In most cases the messages are in XML which includes a header that contains the body length. However we have one vendor who's message are different and don't contain the length of the body.
此供应商消息包含HEADER,BODY和TRAILER.标头是1个字节,是STX(0x02)主体长度可变尾部为2个字节,其中包含一个ETX(0x03)和一个LRC.
This one vendors message contains a HEADER, BODY and TRAILER.The header is 1 byte and is an STX (0x02)The body is variable lengthThe trailer is 2 bytes which contain an ETX(0x03) followed by an LRC.
因此,典型的消息可能看起来像:
So a typical message might look like:
STX BODY ETX LRC
02 37000000 06 18
我们最初使用DelimiterBasedFrameDecoder将ETX定义为定界符,但是当我们这样做时,我们会松开消息中的LRC字节.结果,LRC最终成为我们解码的下一条消息的第一个字节.有没有一种方法可以使用DelimiterBasedFrameDecoder并读取ETX分隔符之后的一个字节?
We initially used the DelimiterBasedFrameDecoder defining the ETX as the delimiter, however when we do that we loose the LRC byte that is part of the message. As a result the LRC ends up being the first byte of the next message that we decode. Is there a way to use the DelimiterBasedFrameDecoder and read one byte past the ETX delimiter?
此外,当我们将响应发送回源时,源将随后向我们发送一个ACK,我们也必须使用ACK来响应.
Further, when we send a response back to the source, the source will then send us an ACK which we have to respond to with an ACK as well.
我认为我们需要一个定制的解码器来读取该字节,如果它是ACK,则它会通知下一个处理程序,否则它将继续读取,直到它从ETX读取了1个字节,然后将该消息发送到下一个处理程序.看起来合理吗?在Netty中,是否有更好的方法或者我想使用的解码器代替DelimiterBasedFraneDecoder?
I am thinking that we need a custom decoder that reads the byte, if it is an ACK then it notifies the next handler, otherwise it continues reading until it reads 1 byte past the ETX and then sends that message on to the next handler. Does that seem reasonable? Is there a better way or is there a decoder in Netty that I might want to use instead of of the DelimiterBasedFraneDecoder?
对此我能提供的任何帮助,将不胜感激!
Any help that I can get on this is appreciated!
谢谢蒂姆
因此,在诺曼的建议下,我创建了以下解码器:
So at Norman's suggestion I created the following decoder:
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");
}
}
我的处理程序使用以下命令初始化...
My Handlers are initialized with the following...
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个字节,但是它引发以下异常....
Everything works as expected, I get my full message including the LRC which is the 1 byte after the ETX, however it throws the following Exception....
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
我不确定为什么会这样...
I am not sure why this is happening...
对我应该看的东西有什么想法吗?
Any thoughts on what I should be looking at?
谢谢蒂姆
推荐答案
您将需要自己的DelimiterBasedFrameDecoder版本来处理这种情况.基本上只是Netty随附的副本的一个副本,但在定界符之后又消耗了1个字节.
You will need your own version of a DelimiterBasedFrameDecoder that handles the case. Basically just a copy of the one shipped with Netty but also consume 1 more byte after the delimiter.
这篇关于Netty自定义DelimiterBasedFrameDecoder的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!