TCP sticky packet analysis and processing TCP sticky packet phenomenon
TCP sticky packet in general, is the sender sent a plurality of packets, to the receiver after sticking together, resulting in the packet can not fully reflect the data sent.
Analysis of the causes of TCP sticky packets
The cause of the TCP sticky packet may be the cause of the sender, or it may be the reason for the recipient.
Sending party
Because TCP needs to be as efficient and reliable as possible, the TCP protocol uses the Nagle algorithm by default to merge the connected small packets and send them one at a time to improve the efficiency of network transmission. However, the receiver does not know that the sender merges the packets, and the merge of the packets does not have a dividing line in the TCP protocol, so this causes the receiver to not restore its original packets.
Receiving party
TCP is based on a "stream". The speed at which the network transmits data may be faster than the speed at which the receiver processes the data, causing the receiver to have multiple packets in the buffer when it reads the buffer. In the TCP protocol, the receiver is reading all the contents of the buffer at once, so it cannot reflect the original data information.
Resolving TCP Sticky Packets
After analyzing the causes of the TCP sticky packet, the paper aims to solve the problem.
Disabling the Negle algorithm
Because the TCP protocol uses the Negle algorithm, it causes sticky packets. So you can disable the Nagle algorithm.
const char chOpt = 1;int nErr = setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char)); if(nErr == -1){ TRACE( "setsockopt() error\n", WSAGetLastError()); return ;}
Although this method can solve the TCP sticky packet to some extent, it does not solve the problem completely. Because the receiver is also the cause of the sticky packet, this method is only valid for the sender. and disable the Nagle algorithm, to some extent, the efficiency of TCP transmission is reduced. Therefore, this is not an ideal method.
Push flag
Push is a flag bit in the TCP header, and the sender can set this flag bit when sending the data. This flag notifies the receiving party to submit the received data to the receiving process. The data described here includes data that is transmitted along with the push package and data that was previously transmitted to the process.
When the server receives this data, it needs to immediately submit the data to the application-tier process without waiting for additional data to arrive.
Setting the push flag also does not completely resolve the TCP sticky packet, but reduces the likelihood of the receiving party sticking the packet. In fact, the current TCP protocol stack can basically handle this problem on its own, rather than handing it over to the application layer. Therefore, setting the push flag is not an ideal method.
Self-tuning Protocol
A custom protocol that divides packets into packets and packages two processes. When the sender sends the data, the data is sent to the packet operation. The packet that is received is required to be unpacked when the receiver receives the data.
Custom protocol, the packet is to send the data to increase the packet header, Baotou contains data size information, the data is followed in the Baotou. Of course, Baotou can also have other information, such as some of the information to do calibration. Here is the main discussion of the problem of TCP sticky, so do not consider the other.
Sender-Side Sealing Package
Package_head Ppackagehead;Package_head Baotou Structural BodyChar packagehead[1024];int Headlen =sizeof (Package_head);int Packgecontextlen =Strlen (Packagecontext);Packagecontext sent data Ppackagehead->ndatalen = Packgecontextlen;The size of the packageChar *packge = (char*)malloc (Headlen + Packgecontextlen);Memory allocation for packagesmemset (packge, 0, Headlen + packgecontextlen); char *packgecpy = (char*) memcpy (Packge, ( Span class= "Hljs-keyword" >char*) &ppackagehead, Headlen); //copy header packgecpy + = Headlen;packge = (char*) memcpy (packgecpy, (char*) &packagecontext, packgeContextLen); //Copy Package Contents int ret = 0;ret = Send (M_hSocket, Packge, Headlen + packgecontextlen, 0); //Send package if (ret = = Socket_error | | ret = = 0) {return ret;}
Receiver Unpacking
Char packagehead[1024];Char packagecontext[1024*20];int Len; Package_head *ppackagehead;Package_head Baotou Structural Bodywhile (M_bclose = =False) {memset (Packagehead,0, sizeof (Package_head)); len = Receivesize (M_TcpSock, (char*) packagehead, sizeof (Package_head)); //receive Baotou if (len = = socket_error) {if (len = 0) {break;} Ppackagehead = (Package_head *) Packagehead; memset (Packagecontext,0, sizeof (Packagecontext)); if (Ppackagehead->ndatalen>0) //receives data {len = Receivesize (M_tcpsock, char*) based on the length of data in the packet header Packagecontext,ppackagehead->ndatalen); }}
Receives a data function of the specified length
Receives data of a specified lengthIntReceivesizechar* strdata, int gLen) {if (strdata = null) return err_badparam; char *p = strdata; int len = gLen; int ret = 0; int Returnlen = 0; while (len > 0) {ret = recv (M_hsocket, p+ (Ilen-len), Ilen-returnlen, 0); if (ret = = Socket_error | | ret = = 0) {return Returnlen;}
This can be achieved by solving the problem of TCP sticky packets. In the actual use of Baotou also with more information, and the end of the package may also be a delimiter, in Redis, FTP is the way to handle.
UDP does not exist sticky pack
Because UDP is not oriented to ' flow ', and UDP is a message boundary. This means that each packet sent by UDP is independent. So UDP does not have a sticky packet problem.
Category: C + + service-side development
TCP Sticky Packets