粘包

什么是粘包:

一.当服务端发送的数据小于客户端接收数据缓存,且发送数据较快,客户端接收的数据就会出现粘包现象,这是由于tcp协议的优化导致,客户端接收数据时并不知道数据的边界。

二.当服务端发送的数据大于客户端接收数据的缓存,客户端需要多次从自己的缓存区提取数据,就出现了粘包现象

解决方法:

提前告诉客户端接收文件的大小

方法一:  每次发送数据时,获取数据长度,把数据长度发送给客户端,再发送真实数据

服务端代码:

from socket import *
import subprocess
import struct
ip_port = ('127.0.0.1', 8000)
back_log = 5
buffer_siza = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
# tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR) #如果当服务端关闭后再打开出现地址重用,无法启用,输入这代码即可解决
tcp_server.bind(ip_port)
tcp_server.listen(back_log)

while True:
    conn, addr = tcp_server.accept()
    print('新的客户端链接是:', addr)
    while True:
        try:
            cmd = conn.recv(buffer_siza).decode('utf-8')
            if not cmd:
                break
            print('收到,开始执行', cmd)
            p1 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE,
                                  stdin=subprocess.PIPE)
            stdder = p1.stderr.read()
             stdout = p1.stdout.read()
            size = len(stdder) + len(stdout)
            date = struct.pack('i', size)
            conn.send(date)
            conn.send(stdder)
            conn.send(stdout)
            print('ok')
        except Exception as e:
            break
    conn.close()

客户端代码:

from socket import *
import struct

ip_port = ('127.0.0.1', 8000)
buffer_siza = 1024
tcp_clien = socket(AF_INET, SOCK_STREAM)
tcp_clien.connect(ip_port)


while True:
    msg = input('-->:')
    if not msg:
        continue
    if msg =='stop':
        break
    tcp_clien.send(msg.encode('utf-8'))
    recv_size = 0
    recv_msg = b''


    t_size = tcp_clien.recv(4)
    size = struct.unpack('i', t_size)[0]
    while recv_size < size:
        recv_msg += tcp_clien.recv(buffer_siza)
        recv_size = len(recv_msg)
    print(recv_msg.decode('gbk'))
tcp_clien.close()

方法二:终极版

通过一个列表,该列表存储文件的一些信息,长度,文件名,md5等信息,先把列表发送,在通过列表里面存的文件大小再接收数据

服务端

from socket import *
import subprocess
import struct
import json
ip_port = ('127.0.0.1', 8000)
back_log = 5
buffer_siza = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
    conn, addr = tcp_server.accept()
    print('新的客户端链接是:', addr)
    while True:
        try:
            cmd = conn.recv(buffer_siza).decode('utf-8')
            if not cmd:
                break
            print('收到,开始执行', cmd)
            p1 = subprocess.Popen(cmd, shell=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE,)
            stdder = p1.stderr.read()
            stdout = p1.stdout.read()
            #建立字典
            header_dic = {
                'filename': 'a.txt',
                'md5': 'xxxx',
                'total_size': len(stdout) + len(stdder)
            }
            #序列化
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('utf-8')
            #发送经过序列化的报头长度
            conn.send(struct.pack('i', len(header_bytes)))
            #发送序列化的真实数据
            conn.send(header_bytes)
            conn.send(stdder)
            conn.send(stdout)
            print('ok')
        except Exception as e:
            break
    conn.close()

客户端:

from socket import *
import struct
import json

ip_port = ('127.0.0.1', 8000)
buffer_siza = 1024
tcp_clien = socket(AF_INET, SOCK_STREAM)
tcp_clien.connect(ip_port)


while True:
    msg = input('-->:')
    if not msg:
        continue
    if msg =='stop':
        break
    tcp_clien.send(msg.encode('utf-8'))
    recv_size = 0
    recv_msg = b''
    #接收报头长度
    obj = tcp_clien.recv(4)
    header_size = struct.unpack('i', obj)[0]
    #接收报头信息
    header_bytes = tcp_clien.recv(header_size)
    #反序列化,提取字典当中存的信息
    header_json = header_bytes.decode('utf-8')
    header_dic = json.loads(header_json)
    total_size = header_dic['total_size']
    while recv_size < total_size:
        recv_msg += tcp_clien.recv(buffer_siza)
        recv_size = len(recv_msg)
    print(recv_msg.decode('gbk'))
tcp_clien.close()
原文地址:https://www.cnblogs.com/zhengyiqun1992/p/10306647.html