tcp协议传输中的粘包问题

什么是粘包问题

  tcp是流体协议. 其nagle算法会将数据量较小. 并且发送间隔时间较短的多个数据包合并为一个发送. 网络传输的时候是一段一段字节流的发送. 在接收方看来根本不知道字节流从何开始. 在哪里结束. 所以粘包问题就是接收方不知道消息之间的界限. 不止到一次性提取多少数据导致的

  而udp协议的是面向消息(数据报)的协议. 每一段的udp都是一段消息. 应用程序必须以消息作为单位提取. 不能提取任意自己的数据. 而且udp协议并不建立连接. 只管发送不管对方是否收到. 所以不存在粘包问题

怎么解决粘包问题

​ 设置一个固定的报头. 报头中含有真实数据的长度信息. 然后客户端就可以根据报头的数据去接收相应字节. 从而避免粘包现象. 总结起来就是一开始将真实数据长度通过报头传递给客户端. 后面都是环环相扣

具体代码

​ 前面都是理论部分. 后面咱们来看看怎么进行实操解决粘包问题. 解决粘包问题的关键就是让客户端知道数据之间的界限在哪.

# 服务端.py  # -*- encoding:utf-8 -*- # @time: 2022/7/30 13:07 # @author: Maxs_hu """ 以前有种比较low的方式(alex)是使用time.sleep将数据流之间断开. 当然这种自己设置网络延迟的方式当然是不可取的 """  from socket import * import subprocess import json import struct   socket = socket(AF_INET, SOCK_STREAM)   socket.bind(('127.0.0.1', 8000)) socket.listen(5)  while True:  # 链接循环     print('---服务器开始运行---')     conn, client_addr = socket.accept()     print(client_addr)      while True:         try:             cmd = conn.recv(1024)             if len(cmd) == 0:                 break             obj = subprocess.run(cmd.decode('utf8'),                                  shell=True,                                  stdout=subprocess.PIPE,                                  stderr=subprocess.PIPE,                                  encoding='gbk'                                  )             stdout = obj.stdout.encode('utf8')             stderr = obj.stderr.encode('utf8')             data_size = len(stderr+stdout)             # 1. 制作合理的表头数据             header_dic = {                 'filename': 'a.txt',                 'total_size': data_size,                 'hashlib': 'fdfadfadf343jkafjdxkfjc'             }             # 将字典转化成可以传输的格式. 并计算出len             header_json = json.dumps(header_dic)             header_byte = header_json.encode('utf8')             header_len = struct.pack('i', len(header_byte))              # 1. 先将表头长度进行传递             conn.send(header_len)              # 2. 再将表头数据进行传输             conn.send(header_byte)              # 3. 在传输真实的数据             conn.send(stderr+stdout)         except ConnectionResetError:             break      conn.close()  
# 客户端.py  # -*- encoding:utf-8 -*- # @time: 2022/7/30 13:07 # @author: Maxs_hu from socket import * import struct import json   client = socket(AF_INET, SOCK_STREAM) client.connect(('127.0.0.1', 8000))  while True:     cmd = input('请输入命令>>>').strip()     if len(cmd) == 0:         break     client.send(cmd.encode("utf8"))     # 1. 先接收表头长度     header_len = client.recv(4)     header_size = struct.unpack('i', header_len)[0]      # 2. 根据表头的长度去接收表头     header = client.recv(header_size)      # 解析表头数据     header_dic = json.loads(header.decode('utf8'))     print(header_dic)     total_size = header_dic['total_size']      recv_size = 0     data = b''     while recv_size < total_size:         data += client.recv(1024)         recv_size = len(data)     print(data.decode('utf8')) client.close()   

发表评论

相关文章

当前内容话题