Encoder for binary protocol
Bruno de Carvalho
kindernade at gmail.com
Mon Jul 26 01:38:36 EDT 2010
Deb,
If you want to stick to a dynamically growing structure like
StringBuffer then I'd advise you switch over to ChannelBuffer directly.
Makes more sense as you're dealing with bytes directly rather than
Strings or chars.
However, it's always possible to use objects to represent your messages,
even if they are dynamic.
I've quite often come across scenarios where different types of messages
are exchanged and, much like in your case, apart from the opcode (I
usually call it type), everything else is dynamic. What I do is have a
different Class for each of the opcodes extending an abstract class
which holds all common data (or an Interface if nothing but an opcode is
shared)
Lets assume that your messages only share the opcode field:
public interface Message {
Opcode getOpcode();
}
then you have implementations like:
public class CreateMessage implements Message {
private int field1;
private String field2;
@Override
public Opcode getOpcode() {
return Opcode.CREATE;
}
// getters & setters for fields 1 and 2
}
Your Opcode enum should roughly look like this:
public enum Opcode {
CREATE((byte)0x01),
DELETE((byte)0x02),
SOMETHING_ELSE((byte)0x03);
private byte b;
public Opcode(byte b) {
this.b = b;
}
// useful to write to a ChannelBuffer, when encoding
public byte getByte() {
return this.b;
}
// useful to determine which enum value matches byte, when decoding
public static Opcode fromByte(byte b) {
for (Opcode opcode : values()) {
if (opcode.b == b) {
return opcode;
}
}
throw new IllegalArgumentException("No Opcode for byte: " + b);
}
}
While it's true that the decoder logic will grow more complex, I'd
rather have that complexity at the decoding stage than in the
application code itself.
Overall, I think this solution is more elegant than handling the bytes
at the application layer yourself and you should seriously consider it -
that is unless, of course, your project requirements mandate you to do
otherwise.
Cheers,
Bruno
PS: Pardon any code mistakes, didn't have the IDE open ;)
PS2: If all messages share another field apart from the opcode, say, an
integer message length, I'd go for an AbstractMessage abstract class
rather than an Interface.
On Sun, 2010-07-25 at 22:11 -0700, xtremed wrote:
> Thanks Bruno, for the response.
>
> Yes, we already have the encoded message in a StringBuffer and we need to
> get it across to a ChannelBuffer because as we understand that is the only
> way to get Netty to send it on the socket. Even one copying is ok with us if
> that cannot be avoided.
>
> I missed stating the fact that our message structure itself is dynamic; that
> is depending on the opcode, the structure of the message after that will
> vary. Actually, up to the opcode is a message header (constant) and after
> that the actual message varies depending on the opcode. And there are
> several opcodes and further increasing as the application grows. This means
> that we cannot use a static data structure as you suggested.
>
> May be we could change our message assembling class to use a ChannelBuffer
> in the first place instead of a StringBuffer? Is that a way? Or do you have
> any other suggestion?
>
> Thanks again,
> Deb
More information about the netty-users
mailing list