Learn Netty (ix) lengthfieldbasedframedecoder

Source: Internet
Author: User
Tags readable

Before introduced the Netty natural several kinds of parser, also slightly introduced the Bytetomessagedecoder class, we to Netty decoder still has the certain understanding ~


Today is to introduce a very important decoder in Netty, because compared to other ordinary decoder, this decoder with more scenes, not to say that the other decoder is not important, just because of our business scenario caused by


In today's more popular horizontal split architecture, the RPC protocol is very popular, so that the various projects can be decoupled, making it more flexible, each project through the remote invocation of interaction between each other to define a communication private protocol, and then resolve, so that the data interface can be interacted with


For example, we define a protocol class like this:

Package Com.lyncc.netty.codec.lengthfieldbasedframe;public class Custommsg {//type system number 0xAB denotes a system, 0xBC denotes B system pr        Ivate byte type;        Message Flag 0xAB indicates heartbeat packet 0xBC indicates timeout packet 0xCD business packet private byte flag;        The length of the subject information private int length;        Subject information private String body; Public custommsg () {} public custommsg (byte type, byte flag, int length, String body) {This.typ        e = type;        This.flag = Flag;        this.length = length;    This.body = body;    } public byte GetType () {return type;    } public void SetType (byte type) {This.type = type;    } public byte Getflag () {return flag;    public void Setflag (Byte flag) {This.flag = flag;    } public int GetLength () {return length;    } public void SetLength (int length) {this.length = length;    } public String GetBody () {return body;    The public void Setbody (String body) {this.body = body; }} 
We require two systems to send information in such a format through Netty, which contains several types of information custommsg:

1) type indicates the type of system on the sending side

2) flag indicates the type of message sent, whether it is business data or heartbeat packet data

3) length indicates the size of the subject body

4) body indicates the subject information


With this mutual regulation, the sender and receiver in this format to encode and decode the data, so it is easy to interact with the data, of course, if Netty does not provide any class, we can also encode and decode, but Netty still provides an existing class, so that we can avoid the repetition of the car, And even if we are willing to repeat the car, we do not make the car better than Netty, so we still use it directly


The class provided by Netty is called Lengthfieldbasedframedecoder, which is inconsistent with other decoders where it requires several parameters as its constructor parameters:


Detailed parsing of these parameters can be found in the following documents:

Http://blog.163.com/[email protected]/blog/static/127857195201210821145721/


We also explain these parameters carefully, join us need to parse, join we need to parse the custommsg we just defined, we need to customize a decoder, this class inherits Netty provides Lengthfieldbasedframedecoder:

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Io.netty.buffer.bytebuf;import Io.netty.channel.channelhandlercontext;import Io.netty.handler.codec.lengthfieldbasedframedecoder;public Class    Customdecoder extends Lengthfieldbasedframedecoder {//Determine if the transmitting client transmits data according to protocol, the size of the header information should be byte+byte+int = 1+1+4 = 6        private static final int header_size = 6;        private byte type;        private byte flag;        private int length;    Private String body; /** * * @param maxframelength decoding, the maximum length of each frame data is processed * @param lengthfieldoffset The starting position of the data that holds the length of the frame data in the frame data * @para M lengthfieldlength the length of the field itself that records the length of the frame data * @param lengthadjustment the value defined in the Modify frame data length field, can be negative * @param initialbytestostrip solution The number of bytes that need to be skipped * @param failFast is true when the frame length exceeds maxframelength, immediately report the toolongframeexception exception, false, read the entire frame and then report the exception */P  Ublic customdecoder (int maxframelength, int lengthfieldoffset, int lengthfieldlength, int lengthadjustment, int Initialbytestostrip, Boolean failFast) {super (maxframelength, Lengthfieldoffset, Lengthfieldlength, Lengthadjustment, Initialbytesto    Strip, FailFast); } @Override protected Object decode (Channelhandlercontext ctx, bytebuf in) throws Exception {if (in = = N        ull) {return null; } if (In.readablebytes () < header_size) {throw new Exception ("The Readable information section is smaller than the header information, are you kidding me?")        ");                }//Note that during the reading process, the Readindex pointer is also moving type = In.readbyte ();                Flag = In.readbyte ();                Length = In.readint (); if (in.readablebytes () < length) {throw new Exception ("body field" you tell me the length is "+length+", but the real situation is not so much, you tease me again?)        ");        } bytebuf buf = in.readbytes (length);        byte[] req = new byte[buf.readablebytes ()];        Buf.readbytes (req);                BODY = new String (req, "UTF-8");        Custommsg custommsg = new Custommsg (type,flag,length,body);    return custommsg; }}
The size of the head information we are writing here is 6, the reason in the code is also explained that Byte is a byte, int is four bytes, then the head size is 6 bytes, the next is to define the constructor, the constructor of the arguments in the interpretation of the code has been marked, our actual entry is:

A little explanation:

1) length_field_length refers to our side custommsg LENGTH This property size, our side is the int type, so is 4

2) Length_field_offset refers to the starting position of the LENGTH field on our side, because the type and flag two attributes are preceded, and both are byte, and two are 2 bytes, so the offset is 2.

3) length_adjustment refers to the value of the length of this property, if our body length is 40, sometimes, some people like to write length 44, because the length itself also occupies 4 bytes, so need to adjust, then need-4, We didn't do that on this side, so we could write 0.


OK, here's the complete code:

Customserver.java

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Io.netty.bootstrap.serverbootstrap;import Io.netty.channel.channelfuture;import Io.netty.channel.channelinitializer;import io.netty.channel.ChannelOption; Import Io.netty.channel.eventloopgroup;import Io.netty.channel.nio.nioeventloopgroup;import Io.netty.channel.socket.socketchannel;import Io.netty.channel.socket.nio.nioserversocketchannel;import    Java.net.inetsocketaddress;public class Customserver {private static final int max_frame_length = 1024 * 1024;    private static final int length_field_length = 4;    private static final int length_field_offset = 2;    private static final int length_adjustment = 0;    private static final int initial_bytes_to_strip = 0;        private int port;    public customserver (int port) {this.port = port;        } public void Start () {Eventloopgroup bossgroup = new Nioeventloopgroup (1);        Eventloopgroup Workergroup = new Nioeventloopgroup ();         try {   Serverbootstrap SBS = new Serverbootstrap (). Group (Bossgroup,workergroup). Channel (Nioserversocketchannel.class).                                                 LocalAddress (New Inetsocketaddress (port)). Childhandler (New channelinitializer<socketchannel> () {                             protected void Initchannel (Socketchannel ch) throws Exception { Ch.pipeline (). AddLast (New Customdecoder (max_frame_length,length_field_length,length_field_offset,length_                             Adjustment,initial_bytes_to_strip,false));                        Ch.pipeline (). AddLast (New Customserverhandler ());                                            };             }). Option (Channeloption.so_backlog, $). Childoption (Channeloption.so_keepalive, true);                            Bind port, start receiving incoming connections channelfuture future = Sbs.bind (port). sync ();             System.out.println ("Server start listen at" + port); Future.channel (). Closefuture (). Sync ();            } catch (Exception e) {bossgroup.shutdowngracefully ();        Workergroup.shutdowngracefully ();        }} public static void Main (string[] args) throws Exception {int port;        if (Args.length > 0) {port = Integer.parseint (Args[0]);        } else {port = 8080;    } new Customserver (port). Start (); }}
Customserverhandler.java

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Io.netty.channel.channelhandlercontext;import Io.netty.channel.simplechannelinboundhandler;public class Customserverhandler extends Simplechannelinboundhandler <Object> {    @Override    protected void channelRead0 (Channelhandlercontext ctx, Object msg) throws Exception {        if (msg instanceof custommsg) {            custommsg custommsg = (custommsg) msg;            System.out.println ("Client->server:" +ctx.channel (). Remoteaddress () + "send" +custommsg.getbody ());}}            
Customclient.java

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Io.netty.bootstrap.bootstrap;import Io.netty.channel.channelfuture;import Io.netty.channel.channelinitializer;import io.netty.channel.ChannelOption; Import Io.netty.channel.eventloopgroup;import Io.netty.channel.nio.nioeventloopgroup;import Io.netty.channel.socket.socketchannel;import Io.netty.channel.socket.nio.niosocketchannel;public Class    customclient {static final String HOST = System.getproperty ("HOST", "127.0.0.1");    static final int PORT = Integer.parseint (System.getproperty ("PORT", "8080"));    static final int SIZE = Integer.parseint (System.getproperty ("SIZE", "256"));        public static void Main (string[] args) throws Exception {//Configure the client.        Eventloopgroup Group = new Nioeventloopgroup ();            try {Bootstrap b = new Bootstrap ();             B.group (Group). Channel (niosocketchannel.class). Option (Channeloption.tcp_nodelay, True) . handler(New channelinitializer<socketchannel> () {@Override public void Initchannel (socketc                     Hannel ch) throws Exception {Ch.pipeline (). AddLast (New Customencoder ());                 Ch.pipeline (). AddLast (New Customclienthandler ());            }             });            Channelfuture future = B.connect (HOST, PORT). sync ();            Future.channel (). Writeandflush ("Hello Netty Server, I am a common client");        Future.channel (). Closefuture (). sync ();        } finally {group.shutdowngracefully (); }    }}
Customclienthandler.java

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Io.netty.channel.channelhandlercontext;import Io.netty.channel.channelinboundhandleradapter;public class Customclienthandler extends Channelinboundhandleradapter {        @Override public    void Channelactive (Channelhandlercontext ctx) throws Exception {        custommsg custommsg = new Custommsg ((byte) 0xAB, (byte) 0xCD, "Hello,netty". Length (), "Hello,netty");        Ctx.writeandflush (custommsg);    }}
The most important thing is two decoders:

Customdecoder.java

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Io.netty.buffer.bytebuf;import Io.netty.channel.channelhandlercontext;import Io.netty.handler.codec.lengthfieldbasedframedecoder;public Class    Customdecoder extends Lengthfieldbasedframedecoder {//Determine if the transmitting client transmits data according to protocol, the size of the header information should be byte+byte+int = 1+1+4 = 6        private static final int header_size = 6;        private byte type;        private byte flag;        private int length;    Private String body; /** * * @param maxframelength decoding, the maximum length of each frame data is processed * @param lengthfieldoffset The starting position of the data that holds the length of the frame data in the frame data * @para M lengthfieldlength the length of the field itself that records the length of the frame data * @param lengthadjustment the value defined in the Modify frame data length field, can be negative * @param initialbytestostrip solution The number of bytes that need to be skipped * @param failFast is true when the frame length exceeds maxframelength, immediately report the toolongframeexception exception, false, read the entire frame and then report the exception */P  Ublic customdecoder (int maxframelength, int lengthfieldoffset, int lengthfieldlength, int lengthadjustment, int Initialbytestostrip, Boolean failFast) {super (maxframelength, Lengthfieldoffset, Lengthfieldlength, Lengthadjustment, Initialbytesto    Strip, FailFast); } @Override protected Object decode (Channelhandlercontext ctx, bytebuf in) throws Exception {if (in = = N        ull) {return null; } if (In.readablebytes () < header_size) {throw new Exception ("The Readable information section is smaller than the header information, are you kidding me?")        ");                }//Note that during the reading process, the Readindex pointer is also moving type = In.readbyte ();                Flag = In.readbyte ();                Length = In.readint (); if (in.readablebytes () < length) {throw new Exception ("body field" you tell me the length is "+length+", but the real situation is not so much, you tease me again?)        ");        } bytebuf buf = in.readbytes (length);        byte[] req = new byte[buf.readablebytes ()];        Buf.readbytes (req);                BODY = new String (req, "UTF-8");        Custommsg custommsg = new Custommsg (type,flag,length,body);    return custommsg; }}
Customencoder.java

Package Com.lyncc.netty.codec.lengthfieldbasedframe;import Java.nio.charset.charset;import Io.netty.buffer.bytebuf;import Io.netty.channel.channelhandlercontext;import Io.netty.handler.codec.messagetobyteencoder;public class Customencoder extends Messagetobyteencoder<custommsg > {    @Override    protected void encode (Channelhandlercontext ctx, custommsg msg, bytebuf out) throws Exception { C2/>if (null = msg) {            throw new Exception ("MSG is null");        }                String BODY = Msg.getbody ();        byte[] bodybytes = body.getbytes (Charset.forname ("Utf-8"));        Out.writebyte (Msg.gettype ());        Out.writebyte (Msg.getflag ());        Out.writeint (bodybytes.length);        Out.writebytes (bodybytes);            }}
Well, so far the code is all done, run the test:

To start the server side:


After running the client, go back to the server-side console:



Learn Netty (ix) lengthfieldbasedframedecoder

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.