zoukankan      html  css  js  c++  java
  • 自定义报头解决粘包问题

    什么是黏包问题:

      首先黏包问题只会在基于TCP协议的socket编程中出现,出现的原因是:由于TCP是字节流协议,客户端在接受服务短发来的数据时,会把数据组织成数据流接收。若客户端的socket对象调用的recv(size)方法中的size值大于或小于服务端发送的数据的长度,都会使多个数据包合成一个包传送,造成数据的混乱,从而形成黏包。

      解决方法是:自定义报头。中心思想是:服务端定制报头(对发送数据的描述信息),服务端在发送真正的数据之前,先向客户端发送报头,客户端接受到报头之后,先读取报头的内容,让客户端知道数据的长度,从而指定自身recv()方法中size的大小,解决黏包问题。

    代码示例1:

     1 import   socket
     2 import subprocess
     3 import json
     4 import struct
     5 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     6 ip_port = ('127.0.0.1',8855)
     7 server.bind(ip_port)
     8 server.listen(5)
     9 while True:
    10     con,add = server.accept()
    11     print(con)
    12     print(add)
    13     while True:
    14         try:
    15             data_bytes = con.recv(1024)
    16             if not data_bytes:break
    17             cmd = subprocess.Popen(data_bytes.decode('utf-8'),shell=True,
    18                                    stdout=subprocess.PIPE,
    19                                    stderr=subprocess.PIPE)
    20             #从管道读出的数据都是bytes类型,因此在发送到客户端时不需要编码
    21             std_out =  cmd.stdout.read()
    22             std_err =  cmd.stderr.read()
    23             data_size = len(std_out) + len(std_err)
    24             #定制报头
    25             head_dic = {'data_size':data_size}
    26             # 报头处理
    27             head_str = json.dumps(head_dic)
    28             head_bytes = head_str.encode('utf-8')
    29             head_len = len(head_str)
    30             head_size = struct.pack('i',head_len)
    31             # 发送报头长度(发送4个字节)
    32             con.send(head_size)
    33             #发送报头数据
    34             con.send(head_bytes)
    35             # 发送数据
    36             con.send(std_out)
    37             con.send(std_err)
    38         except Exception:
    39             break
    40     con.close()
    41 server.close()
    服务端
     1 import  socket
     2 import struct
     3 import  json
     4 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 ip_port = ('127.0.0.1',8855)
     6 client.connect(ip_port)
     7 while True:
     8     msg = input('>>>:')
     9     if not msg:continue
    10     client.send(msg.encode('gbk'))
    11     #part 1 收报头长度
    12     head_bytes = client.recv(4)
    13     head_len = struct.unpack('i',head_bytes)[0]
    14     #part 2 收报头数据
    15     dic_bytes = client.recv(head_len)
    16     head_str = dic_bytes.decode('gbk')
    17     head_dic = json.loads(head_str)
    18     data_size = head_dic['data_size']
    19     print(data_size)
    20     #part 3 收数据
    21         #统计每次循环取数据的长度
    22     recv_size = 0
    23         #累计循环收到的数据
    24     recv_bytes = b''
    25     while recv_size < data_size :
    26         data = client.recv(1024)
    27         recv_size = recv_size + len(data)
    28         recv_bytes = recv_bytes + data
    29     print(recv_bytes.decode('gbk'))
    30 client.close()
    客户端
  • 相关阅读:
    迭代器设计模式
    python中的turtle库绘制图形
    Tesseract-OCR4.0识别中文与训练字库实例
    java图片处理
    Tess4J OCR简单使用教程
    C++ 排列最优解算法思想
    Swing使用JavaFXweb组件
    java专业术语
    java的分数类
    System Rules 更好的测试
  • 原文地址:https://www.cnblogs.com/liuyinzhou/p/7966777.html
Copyright © 2011-2022 走看看