2

私は現在、JavaクライアントがC++サーバーと統合するためのソケット通信を処理するためにNettyを評価しています。メッセージングプロトコルの構造は次のとおりです-

  • (Type)(SubType)(Length)(MessageBody) with size
  • <4bytes> <4bytes><4bytes><...> -長さにはヘッダーが含まれます。

Netty api Iに続いて、LengthFieldBasedFrameDecoderをサブクラス化して、有効な完全なパケットを受信し、受信したタイプに応じて各パケットをデコードします。私が使用しているドキュメントから-

  • lengthFieldOffset = 8
  • lengthFieldLength = 4
  • lengthAdjustment = -12(= HDR1 + LENの長さ、負)
  • initialBytesToStrip = 0

約5分間は正常に動作し(5秒ごとに1つのメッセージが表示されます)、デコードイベントにはメッセージのサイズよりもはるかに短いChannelBufferが含まれます。(クラッシュする前に、このメッセージを何度も受け取りました)。その後、明らかに内部デコードコードでBufferUnderflowExceptionが発生します。私は何か間違ったことをしていますか?LengthFieldBasedFrameDecoderを使用する場合、メッセージの正しいサイズのバッファーを保証する必要がありますか?

LengthFieldBasedFrameDecoderクラス-

public class CisPacketDecoder extends LengthFieldBasedFrameDecoder
{
    public CisPacketDecoder(int maxFrameLength, int lengthFieldOffset,
            int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment,
                initialBytesToStrip);       
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
            throws Exception 
    {       
        CisMessage message = null;      
        int type = buf.getInt(0); //Type is always first int
        CisMessageType messageType = CisMessageType.fromIntToType(type);
        if(messageType != null)
        {
            message = messageType.getObject();
            if(message != null)
            {
                message.decode(buf.toByteBuffer());
            }
            else
            {
                System.out.println("Unable to create message for type " + type);
            }
        }

        //mark the Channel buf as read by moving reader index
        buf.readerIndex(buf.capacity());
        return message;
    }

}

そして、ここでインスタンス化されます。

public class PmcPipelineFactory implements ChannelPipelineFactory 
{

    @Override
    public ChannelPipeline getPipeline() throws Exception
    {
        ChannelPipeline pipeline = Channels.pipeline();

        pipeline.addLast("encoder", new CisPacketEncoder());
        pipeline.addLast("decoder", new CisPacketDecoder(1024, 8, 4, -12, 0));      
        pipeline.addLast("handler", new MsgClientHandler());
        return pipeline;
    }


} 
4

1 に答える 1

3

super.decode(..)を呼び出し、decode(..)メソッドで返されたChannelBufferを操作する必要があります。

したがって、このようになります。

public class CisPacketDecoder extends LengthFieldBasedFrameDecoder {
    public CisPacketDecoder(int maxFrameLength, int lengthFieldOffset,
            int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment,
            initialBytesToStrip);       
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
        throws Exception {

        // THIS IS IMPORTANT!!!!!
        ChannelBuffer decoded = (ChannelBuffer) super.decode(ctx, channel, buf);
        if (decoded == null) {
            return null;
        }

        // NOW ONLY OPERATE ON decoded 
        CisMessage message = null;      
        int type = decoded.getInt(0); //Type is always first int
        CisMessageType messageType = CisMessageType.fromIntToType(type);
        if(messageType != null) {
            message = messageType.getObject();
            if(message != null) {
                message.decode(decoded.toByteBuffer());
            } else {
                System.out.println("Unable to create message for type " + type);
            }
        }
        return message;
    }
}

大文字のコメントを必ず確認してください。

于 2013-01-16T06:57:04.490 に答える