Network programming-socket sticky packet phenomenon

Sticky package phenomenon: multiple packages stick together, that is, the result received this time is the result of the last time

bug1: The server uses the "+" sign when replying to the data

bug2: client specified to receive 1024 bytes

The principle of sticky bag generation :

  • Neither recv nor send directly receives the other party's data, but the operating system memory, not a send corresponding to a recv
  • recv: wait data takes a long time, send: copy data

The sticky packet problem only occurs in TCP, not in UDP

The system will combine the small amount of data and the interval time interval through the algorithm to send together

Simple way to solve the sticky package problem:

Before sending a question, send the data message to the other party so that the other party knows how to receive the data.

Customize the fixed-length data header, and the other party will receive the fixed-length data

Supplementary knowledge: data packaging

import struct
 #packed data 
'l' mode has no rules for packed data
res=struct.pack( ' i ' ,11111 ) print (res,type(res),len(res)) #unpacked data obj=struct.unpack( ' i ' ,res) print (obj)

 

Server:

import socket
import subprocess
import struct
phone = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)
while True:
    conn,client_addr = phone.accept()
     print (client_addr)
     while True:
         try :
             # 1. Receive the command 
            cmd=conn.recv(1024 )
             if  not cmd: break 
            # 2. Execute the command and get the result 
            obj=subprocess.Popen (cmd.decode( ' gbk ' ),shell=True,stdout=subprocess.PIPE,stderr= subprocess.PIPE)
            stdout=obj.stdout.read()
            stderr = obj.stderr.read() #First
             step : make a fixed-length header 
            total_size=len(stdout)+ len(stderr)
            header =struct.pack( ' i ' ,total_size)
             #The second step, send the header 
            conn.send(header)
             # b, and then send the real data 
            conn.send(stdout+stderr) # The "+" sign needs to be optimized 
        except ConnectionResetError:
             break 
    conn.close() #Connection close 
phone.close() #Socket close
View Code

 

  1. Make a fixed-length header
  2. send header to client
  3. send real data

Client:

import socket
import struct
client = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
client.connect(( ' 127.0.0.1 ' ,8080 ))
 #communication loop 
while True:
    cmd =input( ' >> ' ).strip()
     if  not cmd: continue #Avoid the user entering an empty string and cause the client to 
    freeze client.send(cmd.encode( ' utf-8 ' ))
     # 1. Take it first To the data length (packet header), get valid data 
    header=client.recv(4 )
    total_size=struct.unpack('i',header)[0]
    recv_size=0
    recv_data =b '' 
    #Exit the loop until it is received in the loop, and receive data again 
    while recv_size < total_size:
        res=client.recv(1024)
        recv_data+=res
        recv_size += len(res)
     print (recv_data.decode( ' gbk ' ))
 #Close the connection 
client.close()
View Code

 

  1. header first
  2. Parse out the contempt information (data length) of the real data from the header
  3. receive real data

The ultimate solution to the sticky package problem:

server:

  1. Customize a header in the form of a dictionary, containing all the information of the file
  2. Use the struct module to pack file information into a fixed-length header
  3. Send fixed-length file information
  4. send real data
    import socket,os
    import subprocess
    import struct
    import json
    phone = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    while True:
        conn,client_addr = phone.accept()
         print (client_addr)
         while True:
             try :
                 # 1. Receive the command 
                cmd=conn.recv(1024 )
                 if  not cmd: break 
                # 2. Execute the command and get the result 
                obj=subprocess.Popen (cmd.decode( ' gbk ' ),shell=True,stdout=subprocess.PIPE,stderr= subprocess.PIPE)
                stdout=obj.stdout.read()
                stderr = obj.stderr.read() #First
                 step : make a fixed-length header 
                total_size=len(stdout)+ len(stderr)
                header_dic={'filename':"a.txt",
                            'md5':'xxxxxxx',
                            'total_size':len(stdout)+len(stderr)}
                header_json=json.dumps(header_dic)
                header_bytes=header_json.encode('utf-8')
                header =struct.pack( ' i ' ,len(header_bytes))
                 #The second step, first send the length of the 
                header conn.send(header) #The
                 third step, send the header 
                conn.send(header_bytes) #The
                 fourth step, send Real data 
                conn.send(stdout+stderr) # The "+" sign needs to be optimized 
            except ConnectionResetError:
                 break 
        conn.close() #Connection close 
    phone.close() #Socket close
    View Code

client:

  1. Receive a fixed-length header
  2. Get the file information packet size from the header
  3. Get file information data
  4. Get real data size from file info data
  5. receive real data
    import socket
     # client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    # client.connect(('127.0.0.1',8080)) 
    # client.send('hello'.encode('gbk')) 
    # client .send('world'.encode('gbk')) 
    # # while True: 
    # # #1, send command 
    # # cmd=input('>> ').strip() 
    # # if not cmd:continue 
    # # client.send(cmd.encode('gbk')) 
    # # #2, get the result and print it 
    # # data=client.recv(1024).decode('gbk')# 1024 is the pit 
    # # print(data) 
    # client.close()
    import socket
    import struct
    import json
    client = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    client.connect(( ' 127.0.0.1 ' ,8080 ))
     #communication loop 
    while True:
        cmd =input( ' >> ' ).strip()
         if  not cmd: continue #Avoid the user entering an empty string and cause the client to 
        freeze client.send(cmd.encode( ' utf-8 ' ))
         # 1. Take it first To the data length (packet header), get valid data 
        header=client.recv(4 )
        header_size =struct.unpack( ' i ' ,header)[0]
         # 2. Receive header 
        header_bytes= client. recv(header_size)
         # 3. Get useful data from header 
        header_json=header_bytes.decode( ' utf-8 ' )
        header_dic=json.loads(header_json)
        print(header_json)
        total_size=header_dic['total_size']
        recv_size=0
        recv_data =b '' 
        #Exit the loop until it is received in the loop, and receive data again 
        while recv_size < total_size:
            res=client.recv(1024)
            recv_data+=res
            recv_size += len(res)
         print (recv_data.decode( ' gbk ' ))
     #Close the connection 
    client.close()
    View Code

     

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324872579&siteId=291194637