Get started with the previous article Apache Mina (a)-basic knowledge, we can know: Apache Mina Server is a network communication application framework, that is, it is mainly based on TCP/IP, UDP/IP protocol stack Communication Framework (of course, can also provide Java Object serialization service, virtual machine pipeline Communication Service, etc.), Mina can help us quickly develop high-performance, high-scalability network communication applications, Mina provides event-driven, asynchronous (Mina asynchronous IO defaults to using Java NIO as the underlying support) of the programming model.
Getting Started with Apache Mina (ii)--Asynchronous communication mechanism
Apache Mina Getting Started (iii)--Client synchronous communication
Apache Mina Getting Started (four)------Client long connection method to realize disconnection and reconnection monitoring
We can skillfully deal with the problems in the program, but Mina actually has a serious problem, that is, the problem of packet failure--custom or default decoder each read buffered data is limited, that is, the size of the readbuffersize, the default is 2048 bytes, When the packet is larger, it is divided into multiple reads, causing the packet to break. Although we have a rough solution, it is through Acceptor.getsessionconfig (). Setreadbuffersize (newsize) This way to increase the default capacity "The result is that data processing efficiency slows down"
In Mina, the general application scenario with Textline decode and encode is sufficient (textline default delimiter although is \ r \ n, but in fact, the separator can be specified, such as: Newtextlinedecoder (CharSet, Decodingdelimiter);)
Therefore, when the size of the data we receive is not very fixed, and easy to large, the default textline is not appropriate. At this point we need to determine whether the packet is complete before parsing, which can be very cumbersome to handle. Well, fortunately for Mina, Cumulativeprotocoldecoder
Class, from the name of the cumulative protocol decoder, that is, as long as there is data sent, the class will read the data, and then accumulate into the internal iobuffer buffer, but the specific unpacking (the data accumulated to the buffer into a Java object) to the sub-class of Dodecode () Method is done, in fact Cumulativeprotocoldecoder is the Dodecode () method that repeatedly calls the decode () method to the subclass implementation.
The specific execution process is as follows:
A. When your Dodecode () method returns True, the Cumulativeprotocoldecoder decode () method first determines whether you read the data from the internal Iobuffer buffer in the Dodecode () method " The source code is based on the current data read position compared to the previous position, if equal, the data is not read from the cache, conversely, the data has been read from the buffer ", if not, will throw an illegal state exception" throw New IllegalStateException (" Dodecode () can ' t return True when buffer was not consumed. "); ", that is, your Dodecode () method returns True to indicate that the data for the internal iobuffer buffer has been consumed. If the validation passes, then Cumulativeprotocoldecoder checks if there is any data in the buffer that is not read, and if any, continues calling the Dodecode () method "Continue reading from the current read location" without stopping the call to the Dodecode () method.
B. When your Dodecode () method returns false, Cumulativeprotocoldecoder stops the call to the Dodecode () method, but at this point, if the data still has not been read, it will contain the remaining data Iobuffer The buffer is saved to iosession so that the next time the data arrives you can extract the merge from the iosession. If you find that this data is all read, empty the iobuffer buffer.
In short, when you think that the data read is enough to decode, then the part of the data is decoded first, and then the cache to determine whether there is still data, if any, return true, or return false. The most important job of this cumulativeprotocoldecoder is to help you complete the data accumulation, because this job is very cumbersome.
The main code is the decoder:
/** * Decoder * inherits the Cumulativeprotocoldecoder class, realizes to the Mina to break the packet, the sticky packet problem solves * Main idea: * 1, determines whether the current cache goes in the existence data, if exists, then carries on the subsequent processing. * 2, to obtain the message data "message specification: Length (2 bytes) + method Number (1 bytes) + content", first get the length, determine whether the buffer remaining data length and message length is equal, if not equal, representing the message data is incomplete, * return false, need to read from the cache * 3 , equal, then get the method number, content, get to the content, then the part of the complete data to handler processing, * 4, determine if the buffer is still there data, if present, on behalf of the message is also sticky packet.
Returns True. * @author LIUC * @date 2017-12-22 * */public class Bytearraydecoder extends Cumulativeprotocoldecoder {private S
Tatic final Logger Logger = Logger.getlogger (Nsprotocaldecoder.class);
Private final Charset Charset = Charset.forname ("GBK");
Maximum length of the request message 100k private int maxpacklength = 102400;
public int getmaxpacklength () {return maxpacklength; } public void Setmaxpacklength (int maxpacklength) {if (maxpacklength <= 0) {throw new Illega
Largumentexception ("Maximum request message length:" + maxpacklength);
} this.maxpacklength = Maxpacklength; } @Override protected Boolean Dodecode (iosession session, Iobuffer in, protocoldecoderoutput out) throws Exception {//1, first determine if the data exists if (in.remaining ()
> 0) {in.mark ();
1. Get length byte[] sizebytes = new byte[2];
In.get (sizebytes,0,2);//read 2 bytes byte[] Length_byte_arr = new byte[]{0,0,0,0};
LENGTH_BYTE_ARR[2] = sizebytes[0];
LENGTH_BYTE_ARR[3] = sizebytes[1];
Gets the length of int length = Bytetools.bytearraytoint (Length_byte_arr);
Length-2 is reduced by 2 because it reads two bytes of length if (in.remaining () < length-2) {in.reset ();
Represents incomplete message, need to read the buffer again data return false;
}//Get method number byte[] Funcidbytes = {in.get ()};
byte[] Funcid_byte_arr = new byte[]{0,0,0,0};
FUNCID_BYTE_ARR[3] = funcidbytes[0];
Gets the length int funcid = Bytetools.bytearraytoint (Funcid_byte_arr); System.out.println ("3================================== "+in.remaining ());
Get content//Read message body contents int oldlimit = In.limit ();
Logger.debug ("Limit:" + (in.position () + length));
Current read position + total length-length of bytes read in front in.limit (in.position () + length-3);
String content = in.getstring (Charset.newdecoder ());
In.limit (Oldlimit);
Logger.debug ("Message body content:" + content);
Basemessageforclient message = new Basemessageforclient ();
Message.setlength (length);
Message.setfuncid (FUNCID);
Message.setcontent (content);
Out.write (message); Represents a subsequent package that can be re-read, but the previous package has been sent to handler for processing//The problem is known as sticky Packet if (in.remaining () > 0) {RE
Turn true;
}} return false; }
}
The encoder code is as follows:
public class Bytearrayencoder extends Protocolencoderadapter {public
void encode (iosession session, Object message,
protocolencoderoutput out) throws Exception {
//TODO auto-generated method stub
Basemessageforserver Basemessage = (basemessageforserver) message;
Iobuffer buffer = iobuffer.allocate (n);
Buffer.setautoexpand (true);
Buffer.put (Bytetools.inttobytearray (Basemessage.getlength () +3, 2));//Kanenaga
buffer.put (bytetools.inttobytearray (Basemessage.getfuncid (), 1)); /method Number
Buffer.put (Basemessage.getcontent (). GetBytes ());//Content
Buffer.flip ();
Out.write (buffer);
Out.flush ();
Buffer.free ();
}
}
Source code Download Address: http://download.csdn.net/download/u012151597/10168974