Example of a problem resolution for TCP sticky packets in C #

Source: Internet
Author: User
This article is mainly for you to introduce in detail the solution of the TCP sticky packet problem in C #, with a certain reference value, interested partners can refer to

First, the principle of TCP sticky packet production

1.TCP Sticky packet refers to the sender sent a number of packets of data to the receiving party to adhere to a packet, from the receiving buffer, the next packet of data, followed by the end of the packet of data. There are many reasons for the sticky-packet phenomenon, which may be caused by the sender or by the receiver.

2. The sticky packets caused by the sender are caused by the TCP protocol itself, and TCP is often needed to collect enough data to send a packet of data to improve transmission efficiency. If the data sent several times in a row is very small, usually TCP will be based on the optimization algorithm to synthesize the data packets sent out once, so that the receiver received the sticky packet data. The sticky packet caused by the receiver is due to the fact that the receiver user process does not receive the data in time, resulting in sticky packets.

3. This is because the receiver first put the received data in the system receive buffer, the user process from the buffer to fetch data, if the next packet of data arrives before a packet of data has not been taken away by the user process, the next packet of data into the system receive buffer when the previous packet of data is received, The user process takes data from the system receive buffer based on the pre-set buffer size, so that it takes more than one packet of data at a time. 、

Second, the solution principle and code implementation

1. Using Baotou (fixed length, inside the length of the package, the dynamic acquisition of the transmission) + the transport mechanism of the package body.

Headersize Store the length of the package body, its headersize itself is fixed length 4 bytes;

A complete packet (L) =headersize+bodysize;

2. Subcontracting algorithm

The basic idea is to first convert the received data stream, the system buffer data (length set to m) into a predetermined structure data form, take the Structure data length field L, and then calculate the first packet data length according to the Baotou.

m= system buffer size; l= user-sent packet =headersize+bodysize;

1) If l<m, indicates that the data stream contains multiple packets of data, from its head to intercept a number of bytes into the temporary buffer, the rest of the data continues to loop processing, until the end.

2) If l=m, indicates that the data stream content is exactly a complete structure of data (that is, the user-defined buffer equals the system receive buffer size), directly into the temporary buffer.

3) If the l>m, it indicates that the data stream content is not enough to form a complete structure of data, to be left with the next packet of data to be processed.

4) Here is the code implementation (the server side of the Hp-socket framework to receive data)

int headsize = 4;//header length fixed 4 byte[] Surplusbuffer = null;//incomplete packet, user-defined buffer///<summary>///Receive data from client///&LT ;/summary>//<param name= "Connid" > Sessions per customer id</param>//<param name= "bytes" > Buffer data </param >//<returns></returns> private Handleresult onreceive (IntPtr connid, byte[] bytes) {//bytes for system buffering The zone data//bytesread for the system buffer length int bytesread = bytes.   Length;     if (Bytesread > 0) {if (Surplusbuffer = = null)//judgment is not the first time it is received, for NULL is the first time Surplusbuffer = bytes;//put the system buffer data inside the custom buffer else Surplusbuffer = Surplusbuffer.concat (bytes).    ToArray ();//stitching the last remaining package//has finished reading each packet length int haveread = 0;    The length of the totallen here may be greater than the buffer size (because the surplusbuffer here is the system buffer + incomplete packets) int totallen = Surplusbuffer.length;  while (Haveread <= totallen) {//If the remaining packets after n this disassembly are not enough for the length of the packet header//description is the last non-complete packet left after the last read of n full packet if (Totallen      -Haveread < Headsize) {byte[] bytesub = new Byte[totallen-haveread]; Save enough for a complete packetTo Buffer.blockcopy (Surplusbuffer, Haveread, bytesub, 0, Totallen-haveread);      Surplusbuffer = bytesub;      Totallen = 0;     Break     }//If enough for a full package, read header data byte[] Headbyte = new Byte[headsize]; Buffer.blockcopy (Surplusbuffer, Haveread, Headbyte, 0, headsize);//reads header bytes from the buffer int bodysize = Bitconverter.toint32 (He Adbyte, 0);//The length of the package is analyzed from the inside of the Baotou//haveread= is equal to the length of n packets starting from 0; 0,1,2,3....N//If the length of the custom buffer after unpacking N packets is greater than the total length, say the last piece of data is not enough for a complete package.      , Split to save if (Haveread + headsize + bodysize > Totallen) {byte[] bytesub = new Byte[totallen-haveread];      Buffer.blockcopy (Surplusbuffer, Haveread, bytesub, 0, Totallen-haveread);      Surplusbuffer = bytesub;     Break } else {//each package is decomposed, parsed into actual text String strc = Encoding.UTF8.GetString (surplusbuffer, Haveread + headsize, bod      Ysize); Addmsg (String.      Format ("> [onreceive], {0}", strc));      Accumulate the current packet length Haveread = haveread + headsize + bodysize; if (Headsize + boDysize = = bytesread)//If the currently received packet length is exactly equal to the buffer length, the irregular data length to be stitched is 0 {surplusbuffer = null;//set null back to the original state Totallen =  0;//clear 0}}}} return Handleresult.ok; }

This completes unpacking parsing text work. But it's not done yet, and if the code is the client receiving data from the server, then it's no problem.

Take a closer look at IntPtr connid session ID for each connection

Private Handleresult OnReceive (IntPtr connid, byte[] bytes) {}

But the server side also has to identify which session of each packet is generated, because the server side is multi-threaded, multi-user mode, the first packet and the second may come from different sessions of data, so the above code only applies to single-session mode.

I want to solve this problem.

Using C # Security Concurrentdictionary,

The latest code

Thread-Safe Dictionary concurrentdictionary<intptr, byte[]> dic = new concurrentdictionary<intptr, byte[]> (); int headsize = 4;//header Length fixed 4//<summary>////Receive data from client///</summary>//<param name= "Connid" > per guest User's session id</param>//<param name= "bytes" > Buffer data </param>//<returns></returns> Private Handleresult onreceive (IntPtr connid, byte[] bytes) {//bytes for system buffer data//bytesread for system buffer length int bytesread = BYTES.L   Ength;    if (Bytesread > 0) {byte[] surplusbuffer = null; if (DIC. TryGetValue (Connid, out Surplusbuffer)) {byte[] curbuffer = Surplusbuffer.concat (bytes). ToArray ();//splicing the last remaining packet//update session ID of the latest byte dic.     Tryupdate (Connid, Curbuffer, Surplusbuffer); Surplusbuffer = curbuffer;//Synchronization} else {//Add the session ID of bytes dic.     TryAdd (Connid, bytes);    Surplusbuffer = bytes;//Synchronization}//has finished reading each packet length int haveread = 0; The length of the totallen here may be greater than the buffer size (because the surplusbuffer here are system buffers + incomplete packets) int Totallen = surplusbuffer.length;  while (Haveread <= totallen) {//If the remaining packets after n this disassembly are not enough for the length of the packet header//description is the last non-complete packet left after the last read of n full packet if (Totallen      -Haveread < Headsize) {byte[] bytesub = new Byte[totallen-haveread];      Save enough for a complete packet buffer.blockcopy (Surplusbuffer, Haveread, bytesub, 0, Totallen-haveread); Dic.      Tryupdate (Connid, Bytesub, Surplusbuffer);      Surplusbuffer = bytesub;      Totallen = 0;     Break     }//If enough for a full package, read header data byte[] Headbyte = new Byte[headsize]; Buffer.blockcopy (Surplusbuffer, Haveread, Headbyte, 0, headsize);//reads header bytes from the buffer int bodysize = Bitconverter.toint32 (He Adbyte, 0);//The length of the package is analyzed from the inside of the Baotou//haveread= is equal to the length of n packets starting from 0; 0,1,2,3....N//If the length of the custom buffer after unpacking N packets is greater than the total length, say the last piece of data is not enough for a complete package.      , Split to save if (Haveread + headsize + bodysize > Totallen) {byte[] bytesub = new Byte[totallen-haveread];      Buffer.blockcopy (Surplusbuffer, Haveread, bytesub, 0, Totallen-haveread); Dic. Tryupdate (connId, Bytesub, Surplusbuffer);      Surplusbuffer = bytesub;     Break } else {//each package is decomposed, parsed into actual text String strc = Encoding.UTF8.GetString (surplusbuffer, Haveread + headsize, bod      Ysize); Addmsg (String.      Format ("> {0}[onreceive], {1}", Connid, STRC));      Accumulate the current packet length Haveread = haveread + headsize + bodysize;       if (headsize + bodysize = = bytesread)//If the current received packet length is exactly equal to the buffer length, the length of the irregular data to be stitched is 0 {byte[] xbtye=null; Dic.       Tryremove (Connid, out Xbtye);  Surplusbuffer = null;//Set null back to original state Totallen = 0;//Clear 0}}}} return Handleresult.ok; }

This resolves the reception clutter caused by multi-client sessions. At this point all work is done. The above code is for reference study, if really do not want to be so troublesome. You can directly use the pack model of the Hp-socket communication framework, which automatically implements the problem of solving sticky packets.

Related Article

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.