Look at the API of Delimiterbasedframedecoder, there are examples:
The Channelbuffer received are as follows:
+--------------+ | abc\ndef\r\n | +--------------+
After Delimiterbasedframedecoder (Delimiters.linedelimiter ()), get:
+-----+-----+ | ABC | DEF | +-----+-----+
Instead of
+----------+ | Abc\ndef |
Why?
First, be clear, if not specified, delimiterbasedframedecoder default will remove the delimiter
Next look at Delimiters.linedelimiter (), which returns two sets of delimiter, corresponding to windows and Linux line breaks
public static channelbuffer[] Linedelimiter () { return new channelbuffer[] { Channelbuffers.wrappedbuffer (new byte[] {' \ r ', ' \ n '}, Channelbuffers.wrappedbuffer (new byte[] {' \ n '}), };
Examine the two sets of separators
Programme I
with "\ r \ n" as the separator, the return
Framea = "Abc\ndef"
Programme II
return with "\ n"
Frameb_0 = "ABC"
frameb_1 = "Def\r"
Since the length of the frameb_0 is shorter than the Framea, in this case, Scenario II is used
But there is a question, why not compare all, but only compare frameb_0?
To know, length (FRAMEA) = Length (frameb_0) + length (frameb_1), both equal
At first, I thought, like split, scenario two would return "abcdef\r" one time.
Not actually.
It is encountered with a delimiter and returns a result
This can be demonstrated by the following code:
public class ClientHandler extends Simplechannelupstreamhandler { @Override public void channelconnected ( Channelhandlercontext CTX, channelstateevent e) throws Exception { String msg = "abc\ndef\r\n"; Channelbuffer buff = Channelbuffers.buffer (Msg.length ()); Buff.writebytes (Msg.getbytes ()); E.getchannel (). write (buff); }}
Server:
Bootstrap.setpipelinefactory (New Channelpipelinefactory () {public channelpipeline Getpipeline () throws Exception { Channelpipeline pipeline = Channels.pipeline ();//Set here: Do not remove delimiters, easy to observe pipeline.addlast ("Handler1", New Delimiterbasedframedecoder (8192, False, Delimiters.linedelimiter ())); Pipeline.addlast ("Handler2", New Serverstringhandler ());// print decode result return pipeline; } );
Serverstringhandler:
public class Serverstringhandler extends simplechannelupstreamhandler{ @Override public void messagereceived (Channelhandlercontext ctx, messageevent e) Throws Exception { Channelbuffer buff = (channelbuffer) e.getmessage (); String msg = (string) buff.tostring (Helper.charset_utf8); String s = "abc\n"; The Msg_escape will output "abc\n" instead of "abc" plus a newline String msg_escape = Stringescapeutils.escapejava (msg); System.out.println ("msg =" + Msg_escape);} }
Results Serverstringhandler will be output two times:
msg = Abc\nmsg = def\r\n
View the source code, will be more clear:
public class Delimiterbasedframedecoder extends Framedecoder {private final channelbuffer[] delimiters; Private final int maxframelength;/* Returns the result, whether the usual call to remove the delimiter is to remove the delimiter, such as New Delimiterbasedframedecoder (8192, Delimiters.linedelimiter ()) is equivalent to the new Delimiterbasedframedecoder (8192,/*stripdelimiter=*/true, Delimiters.linedelimiter ()) */private Final Boolean stripdelimiter; @Override protected Object decode (Cha Nnelhandlercontext CTX, channel channel, Channelbuffer buffer) throws Exception {//Try all delimiters and choose The delimiter which yields the shortest frame. int minframelength = Integer.max_value; Channelbuffer Mindelim = null;/* iteration for each delimiter, try to decode, and then choose the shortest that returns "delimiter frame" in indexof this method */for ( Channelbuffer delim:delimiters) {int framelength = indexOf (buffer, delim); if (framelength >= 0 && framelength < minframelength) {minframelength = Framelength; MiNdelim = Delim; }} if (Mindelim! = null) {int mindelimlength = mindelim.capacity (); Channelbuffer frame; if (stripdelimiter) {frame = Buffer.readbytes (minframelength); Buffer.skipbytes (mindelimlength); } else {frame = Buffer.readbytes (minframelength + mindelimlength); } return frame; }}/* the frame (haystack) to find the first delimiter (needle), this position is recorded as I return (I-haystack.readerindex), that is, the length of the first sub frame after separation can be seen, it is " Find one and return a "*/private static int indexOf (Channelbuffer haystack, channelbuffer needle) {//Traversal haystack for each byte for (int i = Haystack.readerindex (); I < Haystack.writerindex (); i + +) {int haystackindex = i; int Needleindex;/*haystack Whether delimiter appears, note delimiter is a channelbuffer (byte[]) For example haystack= "Abc\r\ndef", needle= "\ r\n "Then when haystackindex=3, found" \ r ", at this time needleindex=0 continue to execute the loop, haystackindex++,needleindex++, found" \ n "So far, the entire needle matchThe program then executes to the IF (Needleindex = = Needle.capacity ()) and returns the result */for (Needleindex = 0; Needleindex < needle.capacity (); Needleindex + +) {if (Haystack.getbyte (haystackindex)! = Needle.getbyte (Needleindex)) { Break } else {haystackindex + +; if (Haystackindex = = Haystack.writerindex () && Needleindex! = needle.capacity ()-1) { return-1; }}} if (Needleindex = = Needle.capacity ()) {//Found the needle from The haystack! return I-haystack.readerindex (); }} return-1; }}
Netty Source Learning-delimiterbasedframedecoder