Socket-stick package, socket-stick
Reference blog: http://www.cnblogs.com/kex1n/p/6502002.html
I. Package sticking
In the socket transmission Big Data article in the previous article, we can smoothly transmit data. It seems that we have done a good job and can receive it. But there is still a problem hidden. Please refer to the following situation:
We can see the location where the error occurred. Let's take a look at the specific situation.
This function is used to determine the data size in the previous article. That is, when the server sends the data size to the client and then receives the data, to determine whether all data is received.
Let's take a look at the server code:
# The server first sends the data size to the client for comparison with conn. send (str (len ('{}'. format (performance_res ). encode ('utf-8 '))). encode ('utf-8') # send data conn. send ('{}'. format (performance_res ). encode ('utf-8 '))
The first code serves to send the data size, and the second is to send the data itself. We can tell from an error that the data sent for the first time contains not only the data size, that is, the data length, but also part of the data sent for the second time. So, of course, there is no way to use the int character in str format, and an error is returned. But why is the sent data confused? why?
Ii. Socket stick package
Comrades, this is a sticky package, that is, the data sent before and after is combined at the receiving end. The package sticking phenomenon does not always appear every time. I tried it for 20 or 30 times before it finally appeared. So how did we get stuck? I know little about it now. I can only talk a little about it. Take a note first and then learn about it slowly.
In terms of phenomena, the sticking package means that the latter data is received at the end of the previous data. The effect is that if the data formats of the two packages are different, they must be used to deal with different problems, for example, if one of the above values is int and the other is str, an error occurs. Even if the data format is the same, but the front and back data are connected together, the receiver may not know its intention.
2.1 consider sticking packets
1) if tcp is used to send data each time, a connection is established with the other party. After the two parties send a piece of data, the connection is closed so that no packet sticking problem occurs. To close a connection, both parties must send a close connection. After the data is sent and received, both parties do not send or receive new data, but close the connection.IgnoreStick package issues.
2) If the sending data has no structure, such as file transmission, the sender only sends the data, and the receiver only receives the data and stores the data.IgnoreStick package
3) do not consider sending data over UDP
4) if the two parties establish a connection, they need to send different structured data within a period of time after the connection. For example, there are several structures after the connection,ConsiderationsStick package
5) after the two parties establish a connection, data will be continuously sent within a period of time,ConsiderationsStick package
2.2 cause of package sticking
Details:
(1) 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.
(2) The user process of the receiver fails to receive data in a timely manner, leading to the sticking of packets. This is because the receiver puts 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.
There are two types of packages to be attached. One is that all the packages that are attached together are complete data packets, and the other is that the packages that are attached together have incomplete packages.
3. How to Solve the Problem of sticking packets
For more information, see. We will handle the above cases.
3.1 exploitation timeout
After the socket stores the data in the buffer zone, the TCP/IP protocol will send the data to the receiver. We add an interval when sending the data twice consecutively, for example:
Conn. send (str (len ('{}'. format (performance_res ). encode ('utf-8 '))). encode ('utf-8') time. sleep (0.5) # interval between two data sending times # send data conn. send ('{}'. format (performance_res ). encode ('utf-8', 'ignore '))
This can solve the problem, but it is obvious that there is a defect. When you let the old driver get off the bus, it will always stop and stop, and he will not hit the hard disk yet? Oh no, it's the steering wheel.
3.2 The receiving end receives the data and returns a confirmation message.
Using the recv () function in the socket is blocked. data will not be sent when the receiving end does not return confirmation. The Code is as follows:
Server:
#-*-Coding: UTF-8-*-import osimport socketserver = socket. socket (socket. AF_INET, socket. SOCK_STREAM) # TCP/IP protocol, TCP. If not entered, it is the default server. bind ('localhost', 9999) server. listen () while True: # multiple clients can be accepted. conn, addr = server. accept () while True: data = conn. recv (1024) if not data: # prevent print ('client has lost... ') break print ('COMMAND execution:', data. decode () has _res = OS. popen (data. decode ()). read () if len (into _res) = 0: print ('COMMAND not found') else: # The server first sends the data size to the client for comparison with conn. send (str (len ('{}'. format (performance_res ). encode ('utf-8 '))). encode ('utf-8') # The clientACK = conn is returned. recv (1024) # send data conn. send ('{}'. format (performance_res ). encode ('utf-8', 'ignore') print ('sending completed ')
View Code
Client:
#-*-Coding: UTF-8-*-import socketclient = socket. socket () client. connect ("localhost", 9999) while True: cmd = input ('>> :'). strip () # determine whether to send NULL data. if yes, resend if len (cmd) = 0: continue else: client. send (cmd. encode ('utf-8') data_size = client. recv (1024) # size of data sent by the receiving server print (data_size) data_length = int (data_size.decode () # Return confirmation client to the server. send ('return to confirm the size of the received data to solve the sticking package '. encode ('utf-8') print ('Return data size :', Data_length) # define the size of received data to 0 received_length = 0 # define the size of received data to 0 received_data = B ''while receiving ed_length <data_length: r_data = client. recv (1024) # The accepted data is bytes-type received_length + = len (r_data) received_data + = r_data else: print ('size of received data: ', received_length) print (received_data.decode ('utf-8', 'ignore! ')
View Code
In fact, there were not many changes, so we added two lines of code, but the steering wheel was saved.