网络编程

解决粘包的终极方案

Posted by youyue on November 29, 2017

#服务端

import subprocess,struct,json
from socket import *
server = socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1',8080))
print(server)
server.listen(5)
while True:
    conn,addr = server.accept()
    print(conn)
    print(addr)
    while True:
        try:
            cmd = conn.recv(1024) # 执行命令
            cmd = cmd.decode('utf-8')
            # 调用subprocess模块,收集执行结果
            obj = subprocess.Popen(cmd,shell = True,
                                   stdout = subprocess.PIPE,
                                   stderr = subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 1.制作报头
            header_dic = {'total_size':len(stdout)+len(stderr)}
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('utf-8')
            header_size = struct.pack('i',len(header_bytes))
            # 2.先发送报头的长度,pack成4位
            conn.send(header_size)
            # 3.发送报头
            conn.send(header_bytes)
            # 4.发送真实数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:break
    conn.close()
server.close()

#客户端

import struct,json
from socket import *
client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    cmd =input('请输入系统命令:').strip()
    if not cmd:continue
    client.send(cmd.encode('utf-8'))
    # 1.先收报头长度
    obj = client.recv(4)
    # 2.再收报头,unpack报头内容
    header_size = struct.unpack('i',obj)[0]
    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.循环收完全部数据
    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()