zoukankan      html  css  js  c++  java
  • 基于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'))


  • 相关阅读:
    【第五年-创业路】
    【工具与解决方案】从做项目中积累学习
    【原理篇】人工智能
    【原理】分布式系统
    攻克Spring
    工具篇集锦
    最好用的JQuery插件集合以及组合拳
    设计模式 之状态模式
    设计模式 之组合模式
    设计模式之 封装算法
  • 原文地址:https://www.cnblogs.com/fanbiyong/p/10180162.html
Copyright © 2011-2022 走看看