zoukankan      html  css  js  c++  java
  • 解决数据传输粘包的问题

    解决数据传输粘包的问题

    服务端

    将数据分为6个阶段发送给客户端

    1. 将报头内容,制作成字典形式
    2. 将字典dumps为json字符串
    3. 把得到的json字符串,转换为二进制bytes
    4. 通过struct.pack把二进制bytes的json字符串计算出4个字节长度
    5. 发送报头 4个字节长度
    6. 发送数据
    import socket
    import subprocess
    import struct
    import json
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)  # 在bing 之前添加; 用于端口重用,释放
    
    phone.bind(("127.0.0.1",8080))
    
    phone.listen(5)
    
    print("server start....")
    
    # 接收消息,和发送消息
    while True:
        conn,client_addr=phone.accept()     # 重新建立连接
    
        while True:
            try:
                cmd = conn.recv(1024)
                print("客户端接收:",cmd.decode("utf-8"))
                if not cmd:break                            # 针对linux 客户端如果断开后,服务端持续打印空
                res = subprocess.Popen(cmd.decode("utf-8"),
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE
                                       )
                stdout = res.stdout.read()
                stderr = res.stderr.read()
    
                # 制作报头
                # header = struct.pack("i",len(stdout)+len(stderr))       # i 表示把长度打包成 4个 字节长度
                header_dic = {"total_size":len(stdout)+len(stderr),"md5":None}
                header_json = json.dumps(header_dic)
                header_bytes = header_json.encode("utf-8")
    
                # 先把报头的长度 打包成 4个 字节长度 发送给客户端
                conn.send(struct.pack("i",len(header_bytes)))
    
    
                # 发送报头
                conn.send(header_bytes)
    
                conn.send(stderr)
                conn.send(stdout)
    
            except Exception:                               # 针对windows 如果客户端断开,服务端也断开
                break
        conn.close()
    phone.close()
    

    客户端

    客户端接收数据

    1. 接收报头长度为struct.pack“i”大小为4个字节,固定长度
    2. 解析报头,取出真正数据报头的长度
    3. 根据数据报头的长度收取bytes字符串长度
    4. 提取报头字典
    5. 从字典中取出,数据的大小
    6. 循环接收数据
    
    import socket
    import struct
    import json
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    phone.connect(("127.0.0.1",8080))
    
    # phone.send("hello".encode("utf-8"))
    while True:
        cmd = input(">>:").strip()
        if not cmd:continue
        phone.send(cmd.encode("utf-8"))
    
        # 接收报头长度,大小为 “i” 定义的4个字节
        struct_res = phone.recv(4)
        # 解析报头,取出报头长度
        header_size = struct.unpack("i",struct_res)[0]
    
        # 在收报头
        header_bytes = phone.recv(header_size)
        # 提取报头字典
        head_json = header_bytes.decode("utf-8")
        head_dic = json.loads(head_json)
        # 取出loads后字典中的total_size的值
        total_size = head_dic["total_size"]
    
        # 根据 取出的 字符串长度,循环接收内容
        recv_size = 0                               # 初始接收字节数为空
        data = b""                                  # 初始数据值为空
        while recv_size < total_size:
            recv_date = phone.recv(1024)
            recv_size += len(recv_date)
            data += recv_date
    
        print("命令结果:", data.decode("gbk"))
    
    phone.close()
    
    
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 基础练习 完美的代价
    Java实现 蓝桥杯VIP基础练习 矩形面积交
    Java实现 蓝桥杯VIP 基础练习 完美的代价
    Java实现 蓝桥杯 蓝桥杯VIP 基础练习 数的读法
    Java实现 蓝桥杯 蓝桥杯VIP 基础练习 数的读法
    Java实现 蓝桥杯 蓝桥杯VIP 基础练习 数的读法
    Java实现 蓝桥杯 蓝桥杯VIP 基础练习 数的读法
    Java实现 蓝桥杯 蓝桥杯VIP 基础练习 数的读法
    核心思想:想清楚自己创业的目的(如果你没有自信提供一种更好的产品或服务,那就别做了,比如IM 电商 搜索)
    在Linux中如何利用backtrace信息解决问题
  • 原文地址:https://www.cnblogs.com/baolin2200/p/7415360.html
Copyright © 2011-2022 走看看