How to properly handle decoder chain in netty?

Jiang Bian timobj at gmail.com
Wed Jun 3 17:34:43 EDT 2009


Frederic -

Thank you for the answer.

I agree with you on the first point. I did tried to extend FrameCoder the
very first time, I can't remember why, but it didn't work (i.e. probably
some stupid reason). So, I looked the FrameCoder's source code and trying to
mimic that, but I forgot the "cumulation" part (in FrameCoder, if it's not
enough to decode, it puts in the cumulation ChannelBuffer). I will
definitely go fix that.

I didn't merge two decoders into one, simply because I have a couple other
decoders for different purpose. So, I feel like it's hard to maintain if I
put everything in one decoder.

Also, I do have a PipelineFactory on the server side.

Thanks again,

Jiang



Frederic Bregier wrote:
> 
> Jiang,
> 
> From what I've read, here are some remarks.
> Perhaps I did not see everything, but it is a start. I think it is normal
> that you have such error
> on transmission, see below why...
> 
> 1) JigDFSCommandDecoder should not be an extend of
> SimpleChannelUpstreamHandler 
> but probably be an extend of FrameDecoder or ReplayingDecoder (see API for
> the difference).
> The reason is that you probably want that the next decoder is only call
> when you have a full
> JigDFSCommand ready to be processed.
> In your code, if you receive part of the chunk (let say the first 8
> bytes), but no more, you will
> continue into the next coder but without having the necessary data.
> Moreover, if you have less
> than 8 bytes for some reasons (TCP splits data, I don't remember how it is
> called, but it is refered in
> the API), you will just ignore this data and loose it (Netty will not by
> default propose you again the
> same bytes). So in both cases, you will loose data because you don't store
> them.
> 
> Except if you use a FrameDecoder (or ReplayingDecoder) as first handler
> since it will remember what
> you have received until it is enough to be a full chunk. Remaining data
> will be passed in the next
> call.
> Take a look at the example in chapter 1.7 of the Netty User Guide.
> 
> 2) The consequence of 1 is that probably your two coders will be put in 1
> since the second
> decodes also some info from the channelBuffer.
> For instance, you will have first to check the first Int as you do:
> 
> protected Object decode(ChannelHandlerContext ctx, Channel channel,
> ChannelBuffer input)
>            ...
>             int magicNumber = input.readInt();
> 	    if (magicNumber != JigDFSCommand.JIGDFS_MAGIC_NUMBER) {
>                     logger.info("It's not a JigDFS message! "
> 			+ input.readerIndex() + "; readables: " + input.readableBytes());
> 		
> 		//logger.debug("Hexdump: " +  ChannelBuffers.hexDump(input));		
>                // here for instance make an exception in order to close
> the channel or send a
>                // message back to the client to inform that it is wrong
> 		throw new MyException("Bad JigDFS, do something with it");
>             }
> 
> Then to check the size according to the command you read too:
>             int command = input.readInt();
>             if(command != JigDFSCommand.CHUNK_DATA){
> 	            return cmd; // or the object you want
>         	}
>            else // try to read the necessary info {
>               if (input.readableBytes() < 24) {		
> 		return null; // not enough data
>             }
> 
> Now read the following parts...
>             int segment = input.readInt();
> 
> 	// read the md5
> 	byte[] md5 = new byte[16];
> 	input.readBytes(md5);
> 
> 	// Read the length field.
> 	int length = input.readInt();
> 
> 	// Make sure if there's enough bytes in the buffer.
> 	if (input.readableBytes() < length) {
> 		return null;
> 	}
>         // now you can read the data
>         byte[] payload = new byte[length];
> 	input.readBytes(payload);
> 
> 	Chunk chunk = new Chunk(payload, md5, segment);
>         // and return the chunk
>         return chunk;
>        }
>     }
> 
> 3) Also, this only works if you use a ChannelPipelineFactory on the server
> side,
> because each coder should be unique for each channel (due to the fact that
> the
> coder will remember the unused bytes from last call). This
> ChannelPipelineFactory
> should create a new coder handler for each connection.
> So for correctness you should also write @ChannelPipelineCoverage("one")
> (it is only "decorative" right now in Netty, but it is intend to know what
> the code is supposed to do).
> 
> 4) Then you just have to insert two handler, one for the coder (the two
> coders in one handler),
> and one for your business work (the one that use Chunk Object or
> JigDFSCommand Object as argument).
> 
> HTH,
> Frederic
> 
> 

-- 
View this message in context: http://n2.nabble.com/How-to-properly-handle-decoder-chain-in-netty--tp3015408p3021231.html
Sent from the Netty User Group mailing list archive at Nabble.com.




More information about the netty-users mailing list