黏包问题
1.服务端连续执行三次recv 2.客户端连续执行三次send """服务端一次性接收到了客户端三次的消息 该现象称为黏包现象""" 服务端: import socket server = socket.socket() server.bind(('127.0.0.1',8082)) server.listen(5) sock, addr = server.accept() data1 = sock.recv(5) data2 = sock.recv(5) data3 = sock.recv(5) print(data1) print(data2) print(data3) 客户端: import socket client = socket.socket() client.connect(('127.0.0.1', 8082)) client.send(b'jason') client.send(b'jerry') client.send(b'kevin') 结果:jasonjerrykevin 黏包现象产生的原因 1.不知道每次的数据到底多大 2.TCP也称为流式协议:数据像水流一样绵绵不绝没有间隔(TCP会针对数据量较小且发送间隔较短的多条数据一次性合并打包发送) 避免黏包现象的核心:明确即将接收的数据具体有多大
struct模块
import struct info = b'hello big baby' print(len(info)) # 数据的真实长度 14 res = struct.pack('i',len(info)) # 将数据打包成固定的长度,i是固定的打包模式 print(len(res)) # 打包之后的长度 4 real_len = struct.unpack('i',res) print(real_len) # 根据固定长度的抱头,解析出真实数据的长度 (14,) desc = b'hello my baby I will take you to play big ball' print(len(desc)) # 数据的真实长度 46 res1 = struct.pack('i',len(desc)) print(len(res1)) # 打包后的长度 4 """黏包问题解决方案1""" # 客户端 # 1.将真实数据转成bytes类型并计算长度 # 2.利用struct模块将真实长度制作成一个固定长度得报头 # 3.将固定长度的报头先发送给服务端 服务端只需要在recv括号内填写固定长度的报头数字 # 4.然后再发送真实的数据 # 服务端 # 1.服务端先接收固定长度的报头 # 2.利用struct模板反向解析出真实数据长度 # 3.recv接收真实数据长度即可 """问题1:struct模块无法打包数据量较大的数据就算换成更大的模式也不行""" """问题2:报头能否传递更多信息,比如电影大小,名称,评价,简介""" """解决方法""" # 字典作为报头打包(效果好,数字小) data_dict= { 'file_name': '野兽先辈摔跤视频.avi', 'file_size': 1213232433543544667, 'file_info': '很好康的', 'file_desc': '经典高清' } import json data_json = json.dumps(data_dict) print(len(data_json.encode('utf8'))) # 真实字典的长度 res = struct.pack('i', len(data_json.encode('utf8'))) print(len(res)) """黏包问题解决最终方案""" # 客户端 # 1.制作真实数据肚饿信息字典 # 2.利用struct模块制作字典的报头 # 3.发送固定长度的报头 # 4.发送字典数据 # 5.发送真实数据 # 服务端 # 1.接收固定长度的字典报头 # 2.解析出字典的长度并接收 # 3.通过字典获取到真实数据的各项信息 # 4.接收真实数据长度
黏包问题的解决
# 服务端 import socket import struct import json server = socket.socket() server.bind(('127.0.0.1',8083)) server.listen(5) sock, addr = server.accept() # 1.接收固定长度的字典报头 data_dict_head= sock.recv(4) # 2.根据报头解析出字典数据的长度 data_dict_len = struct.unpack('i',data_dict_head)[0] # 3.接收字典数据 data_dict_bytes = sock.recv(data_dict_len) data_dict = json.loads(data_dict_bytes) # 自动解码后反序列化 # 4。获取真实数据的各项信息 total_size = data_dict.get('file_size') with open(data_dict.get('file_name'),'wb') as f: f.write(sock.recv(total_size)) """接收真实数据的时候 如果数据量非常大 recv括号内直接填写该数据量 不太合适 我们可以每次接收一点点 反正知道总长度""" total_size = data_dict.get('file_size') recv_size = 0 with open(data_dict.get('file_name'), 'wb') as f: while recv_size < total_size: data = sock.recv(1024) f.write(data) recv_size += len(data) print(recv_size) # 客户端 import socket import os import struct import json client = socket.socket() client.connect(('127.0.0.1',8081)) # 1.获取真实数据大小 file_size= os.path.getsize(r'D:\python9月\代码\day36\03 黏包问题解决方案\有你好看.txt') # 2.制作真实数据的字典数据 data_dict = { 'file_name': '视频资源.txt', 'file_size': file_size, 'file_desc': '保存文档登录后访问', 'file_info': '解压密码:****' } # 3.制作字典报头 data_dict_bytes = json.dumps(data_dict).encode('utf8') data_dict_len = struct.pack('i', len(data_dict_bytes)) # 4.发送字典报头 client.send(data_dict_len) # 报头本身也是bytes类型 我们在看的时候用len长度是4 # 5.发送字典 client.send(data_dict_bytes) # 6.最后发送真实数据 with open(r'D:\python9月\代码\day36\03 黏包问题解决方案\有你好看.txt', 'rb') as f: for i in f: # 一行行发送 和直接一起发效果一样 因为TCP流式协议的特性 client.send(i) # 让其睡眠十秒 import time time.sleep(10)
UDP协议
"""
1.UDP服务端和客户端'各自玩各自的'
2.UDP不会出现多个消息发送合
"""
# 服务端 import socket server = socket.socket(type=socket.SOCK_DGRAM) # UDP协议 server.bind(('127.0.0.1', 8081)) while True: data, addr = server.recvfrom(1024) print('客户端地址>>>:', addr) print('上述地址发送的消息>>>:', data.decode('utf8')) msg = input('>>>:').strip() server.sendto(msg.encode('utf8'), addr) # 客户端1 import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1', 8081) while True: msg = input('>>>:').strip() client.sendto(msg.encode('utf8'), server_addr) data, addr = client.recvfrom(1024) print(data.decode('utf8'), addr) # 客户端2 import socket client = socket.socket(type=socket.SOCK_DGRAM) server_addr = ('127.0.0.1', 8080) while True: msg = input('>>>:').strip() client.sendto(msg.encode('utf8'), server_addr) data, addr = client.recvfrom(1024) print(data.decode('utf8'), addr)
标签:socket,黏包,编程,网络,len,server,dict,报头,data From: https://www.cnblogs.com/juzijunjun/p/16900635.html