Netty 以安全的方式切换/更换净管道(不丢弃消息)

Netty 以安全的方式切换/更换净管道(不丢弃消息),netty,pipeline,Netty,Pipeline,在我们的应用程序中,我们有一个客户机/服务器对,它通过一个小型握手协议P1启动连接,然后切换到另一个协议P2 对于P1协议,使用以下处理程序初始化管道: LengthFieldBasedFrameDecoder P1ProtocolMessageDecoder LengthFieldPrepender P1ProtocolMessageEncoder 成功完成P1握手协议后,通信量应切换到P2协议,在这种情况下,我们首先清除管道,然后添加一组单独的处理程序 当收到P1协议中的最后一条预期消息时

在我们的应用程序中,我们有一个客户机/服务器对,它通过一个小型握手协议P1启动连接,然后切换到另一个协议P2

对于P1协议,使用以下处理程序初始化管道:

LengthFieldBasedFrameDecoder
P1ProtocolMessageDecoder
LengthFieldPrepender
P1ProtocolMessageEncoder
成功完成P1握手协议后,通信量应切换到P2协议,在这种情况下,我们首先清除管道,然后添加一组单独的处理程序

当收到P1协议中的最后一条预期消息时,完成管道切换:

// switch traffic to P2 protocol
clearPipeline();
addNewHandlers();
遇到的问题是LengthFieldBasedFrameDecoder删除会触发意外读取(因为处理程序的ByteBuf中未读取字节)。但是,由于此时管道是空的(已清除,但尚未添加新的处理程序),因此入站消息将被丢弃

是否有任何“安全”的方法来执行管道切换,而不会在处理程序尚未就位时触发不需要的读取

谢谢

稍后编辑:

我在这里读过关于更换解码器的内容: (标题为“用管道中的另一个解码器替换解码器”的部分)

我成功应用的变通方法是:

 removeOldNonByteToMessageHandlers();
 addNewHandlers()
 removeOldByteToMessageHandlers(); 
 // when the "leftover bytes" read is triggered the new handlers are already in place
我的解决方案似乎有问题。
有没有更好的“netty-er”方法来实现这一点?

我注意到,删除顺序中的ByteToMessage处理程序对我来说是不够的,因为它仍然会尝试将它们用于当前消息中的剩余字节

在我的情况下,我有一个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;
    }

}

这是一个棘手的问题吗?不,很抱歉让你困惑。问题是关于内蒂4号。javadoc链接来自v3,它很好地解释了行为,并且对v4也有效-只是组件在v4中的名称不同,我也对这个问题的好答案很感兴趣,因为我有完全相同的用例,并且在开始时进行握手会让一切都有点混乱。
@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;
    }

}