20 Apr 18 Sticky package problem and solution

20 Apr 18
1. Review of the previous lesson
1. TCP (a two-way connection is established) three-way handshake to establish a connection, and four waves to disconnect
Three-way handshake:
   c----syn=1 seq=x--->s
   s----ack=1+x syn=1 seq=y--->c
   c----ack=1+y------->s
   Four waves:
   s------fin=1---------->c
   c------>ack=1--------->s
   c------>fin=1--------->s
   s------>ack=1--------->c
   
127.0.0.1: local loopback address
Regardless of sending and receiving (send, receive), it is directly interacting with its own operating system, and the operating system then transfers the hardware to transmit the information to the other party's operating system.
Also based on the above reasons, there is no one-to-one correspondence between sending and receiving.
 
2、socket
   Socket is an abstraction layer between the application layer and the transport layer, which specifically encapsulates the protocol below the transport layer into an interface for the application layer to use. The application only needs to call the socket interface or write the program according to the socket standard, and the written program naturally follows the tcp/ip protocol.
 
Second, the sticky package problem
TCP, also known as streaming protocol, has two characteristics:
a, like a steady stream of water
b. Optimize the transmission mechanism, and use the NAGLE algorithm to save data with a short time interval and a small amount of data into a wave
The above two characteristics lead to the sticky package problem
 
The idea of ​​​​solving the problem of sticky packets is to know how much to send, and then how much to receive
Note: If you use time.sleep to solve, solve this end, there may be sticky packets on the other end
 
3. Solve the problem of sticky package (basic board)
a. struct module
1) Convert the integer number to the bytes type
2) The converted bytes are of fixed length
 
import struct
res=struct.pack('i',20332)   # ‘i’ --integer
print (res, len (res))
res2=struct.unpack('i',res)
print(res2[0])
 
b. server
from socket import *
import subprocess
import struct
 
server = socket (AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
 
while True:
    conn,client_addr=server.accept() #(connection object, client's ip and port)
    print(client_addr)
    while True:
        try:
            cmd=conn.recv(1024)
            obj=subprocess.Popen(cmd.decode('utf-8'),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
            stdout=obj.stdout.read()
            stderr=obj.stderr.read()
 
            # 1. Make a fixed-length header
            total_size=len(stdout) + len(stderr)
            header=struct.pack('i',total_size)
 
            # 2. Send header
            conn.send(header)
 
            #3. Send real data
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
 
    conn.close()
server.close()
 
c. customer service
from socket import *
import struct
 
client = socket (AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1',8080))
# print(client)
 
while True:
    cmd=input('>>>: ').strip()
    if not cmd:continue
    client.send(cmd.encode('utf-8'))
    #1. Receive fixed-length headers first
    header=client.recv(4)
    #2. Parse the header
    total_size=struct.unpack('i',header)[0]
    print(total_size) #1025
    #3. According to the information in the header, receive real data
 
    recv_size=0
    res = b ''
    while recv_size < total_size:
        recv_data=client.recv(1024)
        res+=recv_data
        recv_size+=len(recv_data)
 
    print(res.decode('gbk'))
client.close()
 
4. Solve the sticky package problem (Ultimate Edition)
a. struct module
import struct
import json
 
header_dic = {
    'total_size': 3122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222121,
    'md5': '123svsaef123sdfasdf',
    'filename': 'a.txt'
}
 
header_json=json.dumps(header_dic)
# print(header_json,type(header_json))
header_bytes=header_json.encode('utf-8')
header_size=len(header_bytes)
 
print(header_size)
obj=struct.pack('i',header_size)
print (obj, len (obj))
 
b. server
from socket import *
import subprocess
import struct
import json
 
server = socket (AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
 
while True:
    conn,client_addr=server.accept() #(connection object, client's ip and port)
    print(client_addr)
    while True:
        try:
            cmd=conn.recv(1024)
            obj=subprocess.Popen(cmd.decode('utf-8'),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
            stdout=obj.stdout.read()
            stderr=obj.stderr.read()
 
            # 1. Make the header
            header_dic={
                'total_size':len(stdout) + len(stderr),
                'md5':'123svsaef123sdfasdf',
                'filename':'a.txt'
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('utf-8')
 
            # 2. Send the length of the header first
            header_size=len(header_bytes)
            conn.send(struct.pack('i',header_size))
 
            # 3. Send header
            conn.send(header_bytes)
 
            # 4. Send real data
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
 
    conn.close()
server.close()
 
c. Client
from socket import *
import struct
import json
 
client = socket (AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1',8080))
# print(client)
 
while True:
    cmd=input('>>>: ').strip()
    if not cmd:continue
    client.send(cmd.encode('utf-8'))
    #1, the length of the first receive header
    header_size=struct.unpack('i',client.recv(4))[0]
 
    #2. Receive header
    header_bytes=client.recv(header_size)
 
    #3. Parse the header
    header_json=header_bytes.decode('utf-8')
    header_dic=json.loads(header_json)
    print(header_dic)
 
    total_size=header_dic[ 'total_size']
    # print(total_size) #1025
    #4. Receive real data according to the information in the header
 
    recv_size=0
    res = b ''
    while recv_size < total_size:
        recv_data=client.recv(1024)
        res+=recv_data
        recv_size+=len(recv_data)
 
    print(res.decode('gbk'))
client.close()
 
5. Procedure for executing commands remotely
a. Client
from socket import *
 
client = socket (AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1',8080))
# print(client)
 
while True:
    cmd=input('>>>: ').strip()
    if not cmd:continue
    client.send(cmd.encode('utf-8'))
    # print('has send')
    res=client.recv(14744)
    # print('has recv')
    print (len (res))
    print(res.decode('gbk'))
 
client.close()
 
b. server
from socket import *
import subprocess
 
server = socket (AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
 
while True:
    conn,client_addr=server.accept() #(connection object, client's ip and port)
    print(client_addr)
    while True:
        try:
            cmd=conn.recv(1024)
            obj=subprocess.Popen(cmd.decode('utf-8'),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
            stdout=obj.stdout.read()
            stderr=obj.stderr.read()
 
            # Send the length of the data first
            total_size=len(stdout) + len(stderr)
            conn.send(total_size)
 
            # send real data
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
 
    conn.close()
server.close()
#Interactive command or cd. . Generally, it needs to be on one machine, and remote control is not recommended. If required, do not execute directly, but simulate execution and send back the simulation results.

Guess you like

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