3

这与我关于统一设置的问题有关(具有持久通道的端口统一

我正在尝试为我的协议发送一个以所有流量为前缀的两个字节序列;我正在这样做,所以当我更新以支持多个协议时,统一处理程序中有一些东西需要嗅探。

在客户端,我在管道末端有一个简单的出站处理程序,它在 ByteBuf 前面加上两个协议标识字节,在服务器管道前面有一个简单的入站处理程序,它将提取它们。我已经设法让它适用于小消息。

服务器队列中的后续处理程序是LengthFieldBasedFrameDecoder我用来构建传入流量(protobuf 对象)的一个处理程序。似乎正在发生的是客户端发送了一个大请求,例如 5M。我得到了一系列通过服务器管道的 64k 缓冲区,其中最后一个缓冲区超过了LengthFieldBasedFrameDecoder等待的阈值,它提取帧并将其传递给处理——这发生正确。

在这一点上,一切都破裂了。据我所知,来自客户端的最后一个 64k 缓冲区包含帧的其余数据、表示下一个请求开始的 2 字节序列,然后是更多内容。我认为这些数据位于帧解码器中,它现在将使用两个协议魔术字节作为下一帧的长度,这是不正确的,并且事情从那里分解。

DelimiterBasedFrameDecoder看起来它在这种情况下会起作用,因为这两个字节序列将分解每个逻辑帧/请求,但在这种情况下这似乎有点过分了。

在这种情况下是否有其他解码器可以使用,还是我应该坚持使用DelimiterBasedFrameDecoder

4

3 回答 3

3

如果您查看LengthFieldBasedFrameDecoder的文档,就会有一个很好的例子来说明如何做您正在尝试做的事情。第四个示例在长度字段前面有一个固定宽度的标头,它配置 FrameDecoder 不剥离任何标头信息。

编辑

对于您的服务器,应首先使用 LengthFieldBasedFrameDecoder,然后检查标头的处理程序可以删除标头和长度字段并相应地传递数据。

在客户端,您可以使用LengthFieldPrepender,然后在此之后添加一个额外的处理程序来添加您的标头数据。

于 2013-08-27T20:19:57.647 回答
0

通常,当您使用长度字段帧解码器时,它应该首先出现在管道中,除非您还使用 SSL 或压缩处理程序,它们将在您的帧处理程序之前运行。最简单的解决方案是将您的协议 id 处理程序放在帧处理程序之后而不是之前。

于 2013-08-26T23:28:10.857 回答
0

在这种情况下,这DelimiterBasedFrameDecoder大致是您想要的,但它不处理作为帧前面而不是结尾的分隔符,所以如果您在这种情况下使用它,它基本上会吃掉您的流量。

使用您的indexOf方法,DelimitedBasedFrameDecoder可以组合一个非常简单的解码器,在服务器通道上使用,该解码器将在吃定界符的同时按定界符序列分割传入流量:

public static final class DelimitingProtocolDecoder extends ByteToMessageDecoder {
    private final ByteBuf mDelimiter;

    public DelimitingProtocolDecoder(final ByteBuf theDelimiter) {
        mDelimiter = theDelimiter;
    }

    @Override
    protected void decode(final ChannelHandlerContext theContext, final ByteBuf theInput, final List<Object> theOutput) throws Exception {
        int aIndex = indexOf(theInput, mDelimiter);

        while (aIndex != -1) {
            if (aIndex > 0) {
                ByteBuf aBuffer = theContext.alloc().buffer(aIndex, aIndex);

                theInput.readBytes(aBuffer);

                theOutput.add(aBuffer);
            }

            theInput.skipBytes(mDelimiter.capacity());

            aIndex = indexOf(theInput, mDelimiter);
        }

        theOutput.add(theInput.readBytes(theInput.readableBytes()));
    }
}
于 2013-08-27T13:34:16.417 回答