基于tcp的粘包处理终极版本

为什么会存在粘包问题?

因为tcp是流失协议 因为接收方不知道发送方的的数据总量和数据划分的界限,

解决的思路:

接收方需要先获取数据的长度

需要发送方先发送数据的长度给接收方

接收方收到长度之后 按照数据长度来获取数据

struct 模块 

可以将python中的数据类型 转换成bytes
第一个参数通常是i 其能转换的数据范围是c语言的int范围
如果int不够 那就用q 表示long long 型
num = 1024
res = struct.pack("i",num) 转成固定4位的bytes字节
res2 = struct.unpack("i",res) 从字节转回整型
服务器端
import socket
import subprocess
import struct
import datetime
import json



server =socket.socket()
server.bind(('127.0.0.1',16888))
server.listen()
# 要求  不仅返回命令的结果 还要返回执行命令的时间  执行时间:2018/12/26
while True:
    client,addr = server.accept()
    while True:
        try:
            #接收命令
            cmd = client.recv(1024).decode('utf-8')
            p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            data = p.stdout.read()
            err_data = p.stderr.read()
            length = len(data)+len(err_data) #真实数据长度

        # 在发送数据之前发送额外的信息
        # t = "{执行时间:%s 真实数据长度:%s" % (datetime.datetime.now(),length)
        # 把要发送的数据先存到字典中
            t ={}
            t["time"] = str(datetime.datetime.now())
            t["size"] = length
            t["filename"] = "a.mp4"

            t_json = json.dumps(t)
            t_data = t_json.encode('utf-8')
            t_length = struct.pack('i',len(t_data))

            client.send(t_length) #1.先发送额外信息的长度
            client.send(t_data) #2.再发送额外信息
            client.send(data) #3.发送真实信息
            client.send(err_data)
        except ConnectionResetError:
            client.close()
            print('客户端关闭,连接中断')
            break

 

客户端

import socket
import struct
import json


c = socket.socket()
c.connect(('127.0.0.1',16888))
while True:
    cmd = input(">>>>>:")
    if not cmd :
        print('命令符不能为空')
        continue
    c.send(cmd.encode('utf-8'))
    #接收额外信息的长度
    length = c.recv(4)

    len_data = struct.unpack('i',length)[0] #接收到的是(72,) 这样类型的元组 取到长度 72
    #接收额外信息
    t_data = c.recv(len_data)
    json_dic = json.loads(t_data.decode("utf-8"))
    print('执行时间%s:'%json_dic["time"])
    data_size = json_dic["size"]  #得到数据长度


    #开始接收真实的数据
    all_data = b'' #储存已经接收到的数据

    rcv_size = 0  #已经接收长度
    while rcv_size < data_size:
        data = c.recv(1024)
        rcv_size +=len(data)
        all_data += data

    print('接收长度%s'%rcv_size)
    print(all_data.decode('gbk'))

 



posted @ 2018-12-26 18:19  语淅淅  阅读(287)  评论(0编辑  收藏  举报