tcp protocol sticking problem

Posted by damnsaiyan on Wed, 31 Jul 2019 04:25:16 +0200

 Sticky packet problem is caused by the way of streaming data transmission in tcp protocol
Give an example:
from socket import *

client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8081))

# Communication cycle
while True:
    cmd=input('>>: ').strip()
    if len(cmd) == 0:continue
    client.send(cmd.encode('utf-8'))
    cmd_res=client.recv(1024)
    print(cmd_res.decode('gbk'))

client.close()
Client
# The server must satisfy at least three points:
# 1. Binding a fixed ip and port
# 2. Always providing services to the outside world,stable operation
# 3. Ability to support concurrency
from socket import *
import subprocess

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8081))
server.listen(5)

# Link loop
while True:
    conn, client_addr = server.accept()
    print(client_addr)

    # Communication cycle
    while True:
        try:
            cmd = conn.recv(1024) #cmd=b'dir'
            if len(cmd) == 0: break  # In the light of linux system
            obj=subprocess.Popen(cmd.decode('utf-8'),
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE
                             )
            stdout=obj.stdout.read()
            stderr=obj.stderr.read()
            print(len(stdout) + len(stderr))
            conn.send(stdout+stderr)
        except ConnectionResetError:
            break

    conn.close()

server.close()

At each run time, when the amount of data is too large, the result of the next command is the result of the last undelivered command.

How to solve the sticky packet problem: the receiver can accurately collect every packet without any residue
from socket import *

client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8081))

# tcp The protocol combines data with a small amount of data and a short time interval to send a datagram.
client.send(b'hello')
client.send(b'world')
client.send(b'egon')
Client
from socket import *

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8081))
server.listen(5)

conn,_=server.accept()
data1=conn.recv(5)
print('First time: ',data1)

data2=conn.recv(5)
print('Second collection: ',data2)

data3=conn.recv(4)
print('Third Harvest: ',data3)
Server

Simple Edition for Solving Sticky Packing Problem

from socket import *
import struct

client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8081))

# Communication cycle
while True:
    cmd=input('>>: ').strip()
    if len(cmd) == 0:continue
    client.send(cmd.encode('utf-8'))
    #1. Receive the headlines first,Get the length of the data from the header
    header=client.recv(4)
    total_size=struct.unpack('i',header)[0]
    #2. Receiving real data
    cmd_res=b''
    recv_size=0
    while recv_size < total_size:
        data=client.recv(1024)
        recv_size+=len(data)
        cmd_res+=data

    print(cmd_res.decode('gbk'))

client.close()
Client
# The server must satisfy at least three points:
# 1. Binding a fixed ip and port
# 2. Always providing services to the outside world,stable operation
# 3. Ability to support concurrency
from socket import *
import subprocess
import struct

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8081))
server.listen(5)

# Link loop
while True:
    conn, client_addr = server.accept()
    print(client_addr)

    # Communication cycle
    while True:
        try:
            cmd = conn.recv(1024) #cmd=b'dir'
            if len(cmd) == 0: break  # In the light of linux system
            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 headline first
            header=struct.pack('i',len(stdout) + len(stderr))
            # 2. Re-send header
            conn.send(header)
            # 3. Finally send real data
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break

    conn.close()

server.close()
Server

Simulated ssh final version for solving sticky package problem

from socket import *
import struct
import json

client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8081))

# Communication cycle
while True:
    cmd=input('>>: ').strip()
    if len(cmd) == 0:continue
    client.send(cmd.encode('utf-8'))
    #1. Receive 4 first bytes,Unscramble the length of the header
    header_size=struct.unpack('i',client.recv(4))[0]

    #2. Receive headers again,Get header_dic
    header_bytes=client.recv(header_size)
    header_json=header_bytes.decode('utf-8')
    header_dic=json.loads(header_json)
    print(header_dic)
    total_size=header_dic['total_size']

    #3. Receiving real data
    cmd_res=b''
    recv_size=0
    while recv_size < total_size:
        data=client.recv(1024)
        recv_size+=len(data)
        cmd_res+=data

    print(cmd_res.decode('gbk'))

client.close()
Client
# The server must satisfy at least three points:
# 1. Binding a fixed ip and port
# 2. Always providing services to the outside world,stable operation
# 3. Ability to support concurrency
from socket import *
import subprocess
import struct
import json

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8081))
server.listen(5)

# Link loop
while True:
    conn, client_addr = server.accept()
    print(client_addr)

    # Communication cycle
    while True:
        try:
            cmd = conn.recv(1024)  # cmd=b'dir'
            if len(cmd) == 0: break  # In the light of linux system
            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 headlines first
            header_dic = {
                'filename': 'a.txt',
                'md5': 'asdfasdf123123x1',
                'total_size': len(stdout) + len(stderr)
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('utf-8')

            # 2. Send 4 first bytes(Length with headers)
            conn.send(struct.pack('i', len(header_bytes)))
            # 3  Re-send header
            conn.send(header_bytes)

            # 4. Finally send real data
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break

    conn.close()

server.close()
Server

 

struct module

import struct

obj1=struct.pack('i',1332)
print(obj1,len(obj1))
# Result: b'4\x05\x00\x00' 4
res1=struct.unpack('i',obj1)
print(res1[0])
#Results: 1332
obj1=struct.pack('q',1332)
print(obj1,len(obj1))
# Result: b'4\x05\x00\x00\x00\x00\x00\x00' 8



import json

header_dic={
                'filename':'a.txt',
                'md5':'asdfasdf123123x1',
                'total_size':12312311111111111111111111111111111111111111123
            }

header_json=json.dumps(header_dic)
print(header_json)
#Result:
# {"filename": "a.txt", "md5": "asdfasdf123123x1", "total_size": 123123111111111111111111. . . }
header_bytes=header_json.encode('utf-8')
print(len(header_bytes))
# Results: 502
Give an example:

Topics: Python socket JSON Linux shell