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()
    
    
    
  • 相关阅读:
    AM335x kernel 4.4.12 i2c eeprom AT24c02驱动移植
    AM335x tscadc platform driver 相关代码跟踪
    Linux kernel make 常用选项介绍
    Linux kernel 文件夹说明
    shell 脚本之获取命令输出字符串以及函数参数传递
    Treeview控件如何获得子节点的所有父节点的名称
    浅谈Delphi高效使用TreeView
    Delphi下Treeview控件基于节点编号的访问
    delphi中TTreeView的使用方法
    学习 TTreeView [2]
  • 原文地址:https://www.cnblogs.com/baolin2200/p/7415360.html
Copyright © 2011-2022 走看看