1

Netty 3.6.6 を使用するアプリケーションがあります。netty を使用して、クライアントからサーバーにランダムなパケット データを送信します。

送信者は次のパイプラインを使用します。

    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() {
                return Channels.pipeline(
                        new LengthFieldPrepender(4) );
            }
    });

パケット データを ChannelBuffer でラップし、受信者がパケットの開始位置と終了位置を認識できるように、ハンドラーに 4 バイトの長さを付加させたいと考えています。

そして受信機は以下を使用します:

        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                    return Channels.pipeline(
                            new NettyReceiveHandler(listener));
            }
        });


    public class NettyReceiveHandler extends LengthFieldBasedFrameDecoder {
        @Override
        protected Object decode(ChannelHandlerContext ctx, Channel channel,
                ChannelBuffer buffer) throws Exception {
            ChannelBuffer decodedBuffer = (ChannelBuffer) super.decode(ctx, channel, buffer);
            if(decodedBuffer == null)
            {
                return null; // not ready yet
            }
            listener.handleObject(decodedBuffer);   
            return null;    // no upstream
        }

        public NettyReceiveHandler(NettyRecvListener listener) {
            super(THREEMiB, 0, 4, 0, 4); 
            this.listener = listener;       
        }

        private static final Logger logger = Logger.getLogger(
                NettyReceiveHandler.class.getName());

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
            logger.severe("Unexpected exception from downstream." + e.getCause());
            e.getChannel().close();
        }

        private final NettyRecvListener listener;
        private static final int THREEMiB = 3*1024*1024;
    }

すべてが期待どおりに機能しているようです。送信者はランダムなサイズの ChannelBuffer を次々と送信し、受信者は同じ ChannelBuffer を同じ順序で受信します。

今私の質問は次のとおりです。

1. 大きな ChannelBuffer をチャネルに書き込むと、いくつかの書き込みに分割されます。たとえば、テストのログにこれが表示されます。

WARNING: The pipeline contains no upstream handlers; discarding: [id: 0xa1b55c95, /127.0.0.1:52359 => localhost/127.0.0.1:9991] WRITTEN_AMOUNT: 131071

したがって、2 つの 1MiB バッファー (bufferA と bufferB) を送信しており、各書き込みが大まかに 8 つの書き込み (bufferA1、bufferA2、... および bufferB1、bufferB2、...) に分割されていると仮定します。ロードまたはレシーバーが誤ってコールバックに多くの時間を費やしている場合)、フレーミングは壊れますか? つまり、bufferA は、受信側で bufferA1、bufferA2、bufferA3、bufferA5、bufferA6、bufferA7、bufferA8、bufferB1 で誤って構成されています。

フレーミングを壊さないという保証はありますか。

2.上流のハンドラーがないため、NettyReceiveHandler::decode で常に null を返すのは正しいアプローチですか?

助けてくれてありがとう。

4

1 に答える 1

2

TCP 接続を想定すると、大量の書き込みがドロップされることはありません。Netty は、書き込み可能になるまでデータをキューに入れます。Netty は、INTEREST_OPSイベントを発生させることによって書き込みキューがいっぱいであることを通知する場合がありますが、さらにデータをキューに入れることを止めることはありません。

個人的には、これを少し違った方法で処理します。LengthFieldBasedFrameDecoder を拡張するのではなく、標準の LengthFieldBasedFrameDecoder と NettyReceiveHandler の 2 つのハンドラーを持つパイプラインを作成します。あとは、messageReceived をオーバーライドして、リスナーを e.getMessage() (または Message イベント パラメータで呼び出したもの) で呼び出すだけです。LengthFieldBasedFrameDecoder のデコード メソッドを呼び出したり、null を返す必要があるかどうかを心配したりする必要はありません。メッセージを処理するだけです。

于 2013-07-08T10:28:07.153 に答える