我正在使用EmbeddedChannel
测试我的handlers
和codecs
来处理以下格式的消息:
+------------+------------------+----------------+
| Header | Payload Length | Payload |
| 16 bytes | 2 bytes | "Some data" |
+------------+------------------+----------------+
首先,我想实现以下目标:
- 创建一个对象来存储头部详细信息,并将解码后的头部对象添加到
ChannelHandlerContext
的AttributeMap
中供以后使用; - 等待/检索整个有效载荷数据;
- 在最终处理程序上提供Header对象和整个有效负载作为
ByteBuf
以路由消息。
我使用以下处理程序:
ByteToMessageCodec<ByteBuf>
来提取头部信息并将其添加到属性列表中。LengthFieldBasedFrameDecoder
读取有效载荷长度并等待/检索整个帧。SimpleChannelInboundHandler
将使用从属性列表中检索的头部对象相应地路由有效负载。
当将消息传递给ByteToMessageCodec
的decode
方法时,头部会被正确地处理和提取。然后我继续将Header对象添加到AttributeMap
中,并添加ByteBuf
(其中readableBytes = 2个字节(有效载荷长度指示器)+有效载荷长度)。
假设有效载荷长度为1020个字节。最初由codec
接收的消息将具有readableBytes = 16字节+2字节+1020字节
。头部由decode
方法读取,然后剩余的可用字节数(1022)将添加到List<Object> out
中。
如果我理解正确,剩余的字节现在将被传递给下一个处理程序,即LengthFieldBasedFrameDecoder
,它将读取长度指示器并将有效负载(1020个字节)传递给SimpleChannelHanlder
,但我一定是错了。
decode
方法再次被调用,使用之前添加到List<Object> out
中的相同1022个字节。
在decode
方法的JavaDoc中,有以下内容:
Decode the from one ByteBuf to an other. This method will be called till either the input ByteBuf
has nothing to read when return from this method or till nothing was read from the input ByteBuf.
这是否意味着将一直调用
decode
,直到readableBytes == 0
?传递其余消息给
LengthFieldBasedFrameDecoder
的最有效方式是什么?我假设
LengthFieldBasedFrameDecoder
需要一个ByteBuf
作为输入,这是否意味着我需要将readerIndex = 0
并向List<Object> out
添加一个ByteBuf
的副本?任何帮助/建议/批评都将不胜感激,我想以尽可能简洁的方式完成此操作。
这是我的
decode
方法:protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
byte [] headerBytes = new byte[HEADER_LENGTH];
in.readBytes(headerBytes, 0, HEADER_LENGTH);
Header header = new Header(headerBytes);
System.out.println("Decoded Header: \n" + header);
//Set the header attribute so it can be used by routing handlers
ctx.attr(ChannelAttributes.HEADER).getAndSet(header);
//pass to next handler
out.add(in);
}
注意:我正在阅读《Netty in Action MEAP v8》
setSingleDecode(true)
正是我所需要的。但是当我在实现一个ByteToMessageCodec
时,我似乎找不到这个方法,只有一个ByteToMessageDecoder
。没关系,我会将编码和解码过程分开处理。感谢提供关于将header
传递到下一个处理程序的提示。然而,通过将其添加到通道的AttributeMap
中并进行ctx.channel().attr(ChannelAttributes.HEADER).set(header)
操作,我成功地设置并检索了header
。这样做有什么不利之处吗? - Ian2thedvsetSingleDecode
只存在于ByteToMessageDecoder
上。至于通道上的属性映射,我看不出任何缺点,这肯定是可行的解决方案。 - knutwalker