Originally I intend to open a separate chapter, specifically to explain the sticky bag and broken bag, but I think this thing I am doing is a headache, but for others may not be so important, so write it here.
So what is a sticky bag or a broken bag?
Sticky pack: We know that the client writes the message to the server, the first thing to write to buffer, in Bytebuffer for example, if you buffer is large enough, and you send a message fast enough, there will be sticky packet phenomenon, for example, you send a message "m| A "and then you have sent out a" m| B "If a sticky packet is generated, the service side reads from the buffer" m|am| B ", such a string; that is, the first message of the client and the second message are glued together.
Broken packet: The packet is often produced after the sticky packet, according to the example, assuming that your buffer size is set to 4 (of course no one will set such a small buffer, for example, do look at it), if you send a message fast enough, it will produce the message sent to the server changed to: The first package "M|am", the second package " | B
In most of the NIO examples, this process is not included, and many examples do not appear in this situation, even the program on-line, if the system is not very stressful, this situation is very small (especially broken packets). Fortunately, in both cases, I have reproduced, I do not do any pause on the client, the for loop sends 100,000 messages to the server, when my buffer server buffer set to 4096, the client buffer is set to 1024, the frequency is still quite high, Buffer can be increased to reduce the occurrence of packets, but can not be avoided, sticky packets are inevitable.
Well, I answered the question mentioned in the 7th point, why should I add four bits to the outer layer of the communication protocol? These four bits are used to mark the length of my message instruction, and once I know the length, I can deal with the broken packet and the sticky packet according to the length. The specific code is as follows:
/** * treatment of packet breakage and adhesive packet phenomenon * * @param socketChannel * @param byteBuffer */ private void handlepacket (Socketchannel socketchannel, bytebuffer bytebuffer) { //tag read buffer start position int location = 0; //if the number of buffers from 0 to limit is greater than the size of the package tag number while ( Bytebuffer.remaining () > packet_head_length) { //Package Size marker string strbsize; // If the byte length of the Endpacket is greater than 0, it is proved that the previous section of the packet contains the Baotou and the package body; &Nbsp; if (EndPacketStr.getBytes (). length > 0) { string strpacket = endpacketstr.substring (packet_head_length) + new String (Bytebuffer.array (), 0, remainbodysize); bytebuffer.position (remainbodysize); location = remainBodySize;// if ( Logger.isdebugenabled ()) { loggEr.info ("Packet processing" (including package body) merged message: " + strPacket + ", buffer position: " + location);// } offerpacket ( Socketchannel, strpacket); //processing finished, clean off the previous section of the packet, so that the next use of; endPacketStr = ""; //the number of bytes of a truncated message after the cleanup is marked; remainBodySize = 0; continue; //if the byte length of the ENDBUFFERSTR is greater than 0, it proves that the previous section of the packet contains only a portion of the Baotou or Baotou and does not contain the package body; } else if (Endbufferstr.getbytes (). length > 0) { strBsize = (New stringbuffer (endbufferstr) Append (new string (Bytebuffer.array (), location, packet_head_length - Endbufferstr.getbytes ())). ToString (); //Move Buffer position bytebuffEr.position (Packet_head_length - endbufferstr.getbytes (). LENGTH); location = bytebuffer.position (); //Get package size int Bytebuffersize = integer.parseint (Strbsize.trim ()); //to merge the messages, save the previous section and the last section of the packet containing only the header or the Baotou part of the packet String strPacket = endbufferstr + (New string (Bytebuffer.array (), packet_head_length - Endbufferstr.getbytes (). length, bytebuffersize)); bytebuffEr.position (location + bytebuffersize);//Move the position of the buffer to the next package body size marker location location = bytebuffer.position (); logger.info ("Broken Packet Processing" ( Not including the package body) merged message: " + strPacket + ", buffer position: " + location"; offerpacket (socketChannel, Strpacket); endbufferstr = ""; continue; //into normal processing (specification of message processing, regardless of packet breakage) } else { strbsize = New string (Bytebuffer.array (), location, packet_head_length); //Move Buffer position bytebuffer.position (location + packet_head_length); } if (logger.isdebugenabled ()) { logger.debug (" Received client package body size: " + strBsize + ", View position change: " + bytebuffer.position ()); } //get the package size &Nbsp; int bytebuffersize = Integer.parseint (Strbsize.trim ()); // If the current position from the buffer to limit is greater than the size of the package, it is proved that the adhesive is wrapped and processed. is equal to the normal package body, there is no sticky packet phenomenon. if (bytebuffer.remaining () >= bytebuffersize) { String strPacket = endBufferStr + (New string ( Bytebuffer.array (), packet_head_length + location, bytebuffersize); bytebuffer.position (Location + packet_head_length + bytebuffersize);//Move the position of the buffer to the next package body size marker location if (logger.isdebugenablEd ()) { logger.debug ("Received Client Package Contents:" + strPacket + ", 2 View position change:" + bytebuffer.position ()); } //wrapping string messages as classes offerpacket (Socketchannel, strpacket); location = bytebuffer.position ();//Set read buffer start position //if the current position of the buffer to limit is less than the package, proving that the packet is broken, Handling of packet breakage } else { &nbSp; endpacketstr = new string ( Bytebuffer.array (), location, bytebuffer.limit () - location); remainBodySize = Integer.parseint (Endpacketstr.substring (0, packet_head_length). Trim ()) - endpacketstr.getbytes ( ) .length + packet_head_length; //has found the first half of the packet, so the entire buffer position adjusted to the end, no longer processed. Wait for the new key to enter Bytebuffer.position (Bytebuffer.limit ()); logger.info ("Processing broken packet contains only the end packet of the complete packet header, buffer position:" + location + ", Buffer limit: " + bytebuffer.limit () + ", containing the remaining characters of the full header: " + endpacketstr + ", Bodysize:" + remainbodysize); } } //processing contains only the message of the previous section of Baotou; if (bytebuffer.remaining () > 0) { // The remaining in the buffer contains only the message endbufferstr = of the previous section of the header. new string (Bytebuffer.array (), location, bytebuffer.limit () - location); logger.info ("Processing broken packet contains only the previous section of the trailer packet, buffer position:" + location + ", buffer limit:" + bytebuffer.limit () + ", does not contain the remaining characters of the full header:" +  ENDBUFFERSTR); //move the buffer pointer to the end, The representative has saved the previous piece of the message and no further processing is required; &nbsP; bytebuffer.position (Bytebuffer.limit ()); } //I don't know if this is going to work, can you free up memory resources bytebuffer.clear (); }
This is likely to be unreasonable because, for a programmer close to 40 years old, logic is already confusing in the mind. I know that there are several situations to be dealt with:
1, sticky bag, good treatment, mainly according to the first four bits of Baotou, determine the size of the package, and then move the location of the buffer (position), the entire package read out into the queue on the line;
2, Broken Package: Broken package is divided into two cases, the first from the beginning of the Baotou broke, this is you can not get the size of the package, you need to save the front of a section, you must wait for the next message to come after, put them together, and then do the processing; the second, has read the complete Baotou, still need to save the Determine how much is behind and then deal with it; I took advantage of three classes of members:
Packet processing, the previous section contains the complete Baotou; private string endpacketstr = "";//packet processing, the previous section does not contain the full header; private string endbufferstr = "";//packet processing, the previous section contains the full header , the size tag of the package body; private int remainbodysize = 0;
Note that members of these classes need to be emptied after use, so that they can be used next time, otherwise they will be out of order. This piece of code, I did not read it again, quite a bother. It would be appreciated if someone could provide a better way.
Implementation of message routing based on NIO (four) main thread of service-side communication (2) processing of broken packets and sticky packets