我已经使用Netty 3.3.1-Final了3周。
我的协议有3个步骤,每个步骤需要一个不同的FrameDecoder:


读取参数
传输一些数据
数据管道相互关闭


我经历了很多我无法理解的“阻塞”问题。终于在我看来,阅读org.jboss.netty.example.portunification示例时,尝试动态更改FrameDecoder时遇到了一些缓冲区问题:一个FrameDecoder的缓冲区(可能)在为下一个更改时不为空。 ..

有没有办法在Netty中轻松地做到这一点?我必须更改我的协议吗?我是否需要编写一个大型FrameDecoder并管理状态?
如果是这样,如何避免具有通用子部分的不同协议之间的代码重复(例如“读取参数”)?

今天,我想到了FrameDecoderUnifier(以下代码)的想法,目的是一种热添加和删除一些FrameDecoder的方法,您怎么看?

谢谢你的帮助!

雷诺

----------- FrameDecoderUnifier类--------------

    /**
     * This FrameDecoder is able to forward the unused bytes from one decoder to the next one. It provides
     * a safe way to replace a FrameDecoder inside a Pipeline.
     * It is not safe to just add and remove FrameDecoder dynamically from a Pipeline because there is a risk
     * of unread bytes inside the buffer of the FrameDecoder you wan't to remove.
     */
    public class FrameDecoderUnifier extends FrameDecoder {

        private final Method frameDecoderDecodeMethod;
        volatile boolean skip = false;
        LastFrameEventHandler eventHandler;
        LinkedList<Entry> entries;
        Entry entry = null;

        public FrameDecoderUnifier(LastFrameEventHandler eventHandler) {
            this.eventHandler = eventHandler;
            this.entries = new LinkedList<Entry>();
            try {
                this.frameDecoderDecodeMethod = FrameDecoder.class.getMethod("decode", ChannelHandlerContext.class, Channel.class, ChannelBuffer.class);
            } catch (NoSuchMethodException ex) {
                throw new RuntimeException(ex);
            } catch (SecurityException ex) {
                throw new RuntimeException(ex);
            }
        }

        public void addLast(FrameDecoder decoder, LastFrameIdentifier identifier) {
            entries.addLast(new Entry(decoder, identifier));
        }

        private Object callDecode(FrameDecoder decoder, ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
            return frameDecoderDecodeMethod.invoke(decoder, ctx, channel, buffer);
        }

        @Override
        protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
            if (entry == null && !entries.isEmpty()) {
                entry = entries.getFirst();
            }

            if (entry == null) {
                return buffer; //No framing, no decoding
            }

            //Perform the decode operation
            Object obj = callDecode(entry.getDecoder(), ctx, channel, buffer);

            if (obj != null && entry.getIdentifier().isLastFrame(obj)) {
                //Fire event
                eventHandler.lastObjectDecoded(entry.getDecoder(), obj);
                entry = null;
            }
            return obj;
        }

        /**
         * You can use this interface to take some action when the current decoder is changed for the next one.
         * This can be useful to change some upper Handler in the pipeline.
         */
        public interface LastFrameEventHandler {

            public void lastObjectDecoded(FrameDecoder decoder, Object obj);
        }

        public interface LastFrameIdentifier {

            /**
             * True if after this frame, we should disable this decoder.
             * @param obj
             * @return
             */
            public abstract boolean isLastFrame(Object decodedObj);
        }

        private class Entry {

            FrameDecoder decoder;
            LastFrameIdentifier identifier;

            public Entry(FrameDecoder decoder, LastFrameIdentifier identifier) {
                this.decoder = decoder;
                this.identifier = identifier;
            }

            public FrameDecoder getDecoder() {
                return decoder;
            }

            public LastFrameIdentifier getIdentifier() {
                return identifier;
            }
        }
}

最佳答案

我认为,应避免使用根据某些状态切换内部解码器并动态添加/删除上层处理程序的帧解码器,因为


难以理解/调试代码
处理程序没有明确定义的职责(这就是为什么要正确删除/添加处理程序?一个处理程序应处理一种或多种(相关)类型的协议消息,而没有许多处理程序处理同一类型的消息)
理想情况下,帧解码器仅提取协议帧,而不基于状态对帧进行解码(此处,帧解码器可以具有内部解码器链来解码帧,并使用已解码的消息触发MessageEvent,上面的处理程序可以对已解码的消息做出反应)。


更新:在这里我考虑了一个协议,其中每个消息可以具有唯一的标记/标识符,并且消息的末尾被清楚地标记(例如Tag Length Value帧格式)

09-30 21:14