安全地切换/替换Netty管道(无需丢失消息)

3
在我们的应用程序中,我们有一个客户端/服务器对,他们使用一个小握手协议P1来初始化连接,之后切换到另一个协议P2。
对于P1协议,管道被初始化为以下处理程序:
LengthFieldBasedFrameDecoder
P1ProtocolMessageDecoder
LengthFieldPrepender
P1ProtocolMessageEncoder

完成P1握手协议后,流量应切换到P2协议,此时我们首先需要清空管道,然后添加一组独立的处理程序。
P2MessageDecoder
P2MessageEncoder
IdleHandler

当收到P1协议中的最后一个预期消息时,会进行管道切换:

// switch traffic to P2 protocol
clearPipeline();
addNewHandlers();

遇到的问题是LengthFieldBasedFrameDecoder的移除会触发意外读取(因为处理程序的ByteBuf中还有未读的字节)。但是,由于此时管道为空(已清除,但尚未添加新处理程序),传入消息将被丢弃。
在处理程序尚未放置的时间内,是否有任何“安全”的方法来进行管道切换而不触发不必要的读取?
谢谢
后续编辑:
我在这里阅读有关替换解码器的信息: (标题为“在管道中用另一个解码器替换解码器”部分)

http://netty.io/4.0/api/io/netty/handler/codec/ReplayingDecoder.html

我成功应用的解决方法是:

我已经成功应用的解决方法是:

 removeOldNonByteToMessageHandlers();
 addNewHandlers()
 removeOldByteToMessageHandlers(); 
 // when the "leftover bytes" read is triggered the new handlers are already in place

我的解决方案似乎有些笨拙。 是否有更好的“netty-er”方式来实现这个?


这是一个 Netty 3 的问题吗? - Norman Maurer
不好意思,没有关于Netty 4的问题。这个javadoc链接是来自v3的,它很好地解释了行为,并且在v4中也是有效的 - 只是在v4中组件的名称不同。http://netty.io/4.0/api/io/netty/handler/codec/ByteToMessageDecoder.html - Edi
我也非常感兴趣得到一个好的答案,因为我有完全相同的用例,而在开始时进行握手会让一切变得有些不可靠。 - Pierre
1个回答

1

我注意到在你的程序中移除ByteToMessage handlers并不够,因为它仍然会尝试对当前消息中剩余的字节使用它们。

在我的情况下,我有一个FixedLengthFrameDecoder,在读取指定数量的字节后,我想将其切换为LengthFieldBasedFrameDecoder。

如果我的消息总共有X个字节,其中前Y个字节是协议信号或“握手”,Z是剩余的字节数,我想通过ByteToMessage处理程序读取前Y个字节,然后通过新的处理程序读取接下来的Z个字节。

@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
    Object handshake = super.decode(ctx, in);

    ctx.pipeline().addFirst(new LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE, 0, 4, 0, 4, true));
    if (in.isReadable()) {
        Object[] response = new Object[] { in.readBytes(in.readableBytes())};
        ctx.pipeline().remove(this);
        return response;
    } else {
        ctx.pipeline().remove(this);
        return handshake;
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接