C # solve the TCP "stick packet" problem,

Source: Internet
Author: User

C # solve the TCP "stick packet" problem,
I. Principles of TCP stick packets

1. TCP stick refers to the packet data sent by the sender to be pasted into a packet upon receiving by the receiver. From the receiving buffer, the header of the next packet is followed by the end of the previous packet. There are many reasons for the phenomenon of sticking packets, which may be caused by both the sender and the receiver.

2. The adhesive packet caused by the sender is caused by the TCP protocol itself. To improve transmission efficiency, the sender often needs to collect enough data before sending a packet of data. If few data is sent several times in a row, TCP will merge the data into a packet based on the optimization algorithm and send the data once. In this way, the receiver receives the data in the sticky packet. The user process of the receiver fails to receive data in time, leading to the packet sticking phenomenon.

3. This is because the receiver first places the received data in the system receiving buffer, and the user process obtains data from the buffer. If the data of the previous packet has not been taken away by the user process when the next packet arrives, then, when the next packet of data is placed in the system's receiving buffer zone, it is received after the previous packet of data, and the user process obtains data from the system's receiving buffer zone according to the preset buffer size, in this way, multiple packets of data are obtained at a time. ,

Ii. Solution Principle and code implementation

1. Use a packet header (fixed length, containing the length of the packet body, which is dynamically obtained upon sending) + transmission mechanism of the packet body.

The HeaderSize contains the length of the package. Its HeaderSize is 4 bytes in length;

A complete packet (L) = HeaderSize + BodySize;

2. Subcontracting Algorithm

The basic idea is to first forcibly convert the received data stream to a predetermined structure data format, namely, the System Buffer data (whose length is set to M), and retrieve the Structure Data Length Field L from it, then, the length of the first packet is calculated based on the packet header.

M = system buffer size; L = user-sent data packet = HeaderSize + BodySize;

1) if L <M, it indicates that the data stream contains multiple packets of data. Several bytes are intercepted from its header and saved to the temporary buffer. The remaining part of the data is processed cyclically until the end of the process.

2) if L = M, it indicates that the data stream content is exactly a complete structured data (that is, the User-Defined buffer is equal to the size of the system receiving buffer), and it can be directly stored in the temporary buffer.

3) if L> M, it indicates that the content of the data stream is not enough to form a complete structured data. It must be merged with the next package of data before processing.

4) The following is code implementation (the server side of the HP-SOCKET framework receives data)

Int headSize = 4; // Fixed Header length 4 byte [] surplusBuffer = null; // incomplete data packet, that is, the User-Defined buffer // <summary> // receives data from the client // </summary> /// <param name = "connId"> session ID </param> /// <param name = "bytes"> buffer data </param> /// <returns> </returns> private HandleResult OnReceive (IntPtr connId, byte [] bytes) {// bytes is the System Buffer data // bytesRead is the System Buffer length int bytesRead = bytes. length; if (bytesRead> 0) {if (surplusBuffer = null) // determines whether the first request is received. if it is null, the first request is surplusBuffer = bytes; // put the System Buffer data in the Custom buffer. else surplusBuffer = surplusBuffer. concat (bytes ). toArray (); // splice the remaining package at the previous time // The length of each data packet has been read. int haveRead = 0; // here, the totalLen length may be greater than the buffer size (because the surplusBuffer here is the System Buffer + incomplete data packets) int totalLen = surplusBuffer. length; while (haveRead <= totalLen, the remaining last incomplete packet if (totalLen-haveRead 

 

This completes the unpacking and parsing of text. But it is not completed yet. If this code is used by the client to receive data from the server, it will be okay.

Take a closer look at IntPtr connId. The session ID of each connection

Private HandleResult OnReceive (IntPtr connId, byte [] bytes)

{

}

However, the server also needs to determine which session is generated for each data packet. Because the server is multi-threaded and multi-user mode, the first data packet and the second data may come from different sessions, therefore, the above Code only applies to single-session mode.

Next I want to solve this problem.

Use c # Safe ConcurrentDictionary, refer to https://msdn.microsoft.com/zh-cn/library/dd287191 (v = vs.110). aspx

Latest code

 

// Thread-safe dictionary ConcurrentDictionary <IntPtr, byte []> dic = new ConcurrentDictionary <IntPtr, byte []> (); int headSize = 4; // The header length is fixed 4 /// <summary> // receives data from the client // </summary> /// <param name = "connId"> each customer session ID of </param> /// <param name = "bytes"> buffer data </param> /// <returns> </returns> private HandleResult OnReceive (IntPtr connId, byte [] bytes) {// bytes is the System Buffer data // bytesRead is the System Buffer length int bytesRead = bytes. length; if (bytesRead> 0) {byte [] surplusBuffer = null; if (dic. tryGetValue (connId, out surplusBuffer) {byte [] curBuffer = surplusBuffer. concat (bytes ). toArray (); // splice the last remaining package // update the latest byte dic of the session ID. tryUpdate (connId, curBuffer, surplusBuffer); surplusBuffer = curBuffer; // synchronization} else {// Add the bytes dic of the session ID. tryAdd (connId, bytes); surplusBuffer = bytes; // synchronous} // The length of each data packet has been read. int haveRead = 0; // here, the totalLen length may be greater than the buffer size (because the surplusBuffer here is the System Buffer + incomplete data packets) int totalLen = surplusBuffer. length; while (haveRead <= totalLen, the remaining last incomplete packet if (totalLen-haveRead 

This solves the confusion caused by multi-client sessions. Now all work has been completed. The above code is for reference and learning. You can directly use the PACK model of the HP-SOCKET communication framework, which automatically solves the problem of sticking 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.