!!!!!!只有TCP有粘包现象,UDP永远不会粘包
什么是黏包?
接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
黏包问题的产生原因:
接收方 不知道对方发了多少数据
而TCP 会把所有收到的数据 拼接到一起 放到系统缓存中
UDP 不会黏包 因其实基于数据包发送数据
黏包问题的解决方法:
发送方 先发送数据长度 接收方先接收长度 长度必须固定字节
自定义报头 不仅可以传输 数据长度 还能添加任意额外信息(报头格式建议使用json 可以跨平台)

1 import socket 2 import subprocess 3 import struct 4 server = socket.socket() 5 server.bind(("127.0.0.1",9090)) 6 server.listen() 7 8 while True: 9 client,addr = server.accept() 10 while True: 11 try: 12 # 接收命令 13 cmd = client.recv(1024).decode("utf-8") 14 p = subprocess.Popen(cmd,shell=True,stdout=-1,stderr=-1) 15 # data与err_data 都是采用的系统编码 windows是GBK 16 data = p.stdout.read() 17 err_data = p.stderr.read() 18 19 print("数据长度:%s" % (len(data) + len(err_data))) 20 21 # 先发送长度给客户端 22 length = len(data) + len(err_data) 23 24 len_data = struct.pack("i",length) 25 # 先发送长度 在发真实数据 有可能 长度数据和真实数据黏在一起 而接收方不知道长度数据的字节数 导致黏包 26 # 解决的方案就是 长度信息占的字节数固定死 整数 转成一个固定长度字节 27 28 client.send(len_data) 29 30 client.send(data) 31 client.send(err_data) 32 except ConnectionResetError: 33 client.close() 34 print("连接中断......") 35 break

1 import socket 2 import struct 3 4 c = socket.socket() 5 c.connect(("127.0.0.1",9090)) 6 while True: 7 cmd = input(">>:").strip() 8 9 c.send(cmd.encode("utf-8")) 10 11 # 先接收长度 长度固定为4个字节 12 length = c.recv(4) 13 len_data = struct.unpack("i",length)[0] # 转换为整型 14 print("数据长度为%s" % len_data) 15 16 all_data = b"" # 存储已接收数据 17 rcv_size = 0 # 已接收长度 18 # 接收真实数据 19 # 循环接收 直到 接收到的长度等于总长度 20 while rcv_size < len_data: 21 data = c.recv(1024) 22 rcv_size += len(data) 23 all_data += data 24 25 print("接收长度%s" % rcv_size) 26 print(all_data.decode("gbk"))
struct 模块的使用
struct 可以将python中的数据类型转换为bytes类型

1 num = 1024 2 3 import struct 4 5 # 该函数 将一个python的数据转成bytes 6 # 第一个参数通常是i 其能转换的数据范围是c语言的int范围 7 # 如果int不够 那就用q 表示long long 型(具体可参照官方文档,一般情况下i已经足够使用) 8 res = struct.pack("i",num) 9 print(res) 10 print(len(res))

1 num = 1024 2 3 import struct 4 5 res = struct.pack("i",num) 6 # 从字节转回整型 7 res2 = struct.unpack("i",res) 8 print(res2[0])
黏包问题高级解决方案

1 import socket 2 import subprocess 3 import datetime 4 import json 5 import struct 6 7 # 创建对象 8 soc = socket.socket() 9 10 # 绑定ip 和 端口 11 soc.bind(('127.0.0.1', 8888)) 12 13 # 监听 14 soc.listen() 15 16 while True: 17 client, addr = soc.accept() 18 while True: 19 try: 20 # 接收命令 21 cmd = client.recv(1024).decode('utf-8') 22 p = subprocess.Popen( 23 cmd, 24 shell=True, 25 stdout=subprocess.PIPE, 26 stderr=subprocess.PIPE 27 ) 28 # data 与err_data 都是采用系统编码 Windows 采用'GBK' 29 data = p.stdout.read() 30 err_data = p.stderr.read() 31 32 # 计算真实数据长度 33 length = len(data) + len(err_data) 34 35 t = {} 36 t['time'] = str(datetime.datetime.now()) 37 t['size'] = length 38 39 # 得到json格式字符串 40 t_json = json.dumps(t) 41 # 将json转换为字节 42 t_data = t_json.encode('utf-8') 43 t_length = struct.pack('i', len(t_data)) 44 45 # 发送额外信息长度 46 client.send(t_length) 47 # 发送额外信息 48 client.send(t_data) 49 50 # 发送真实数据 51 client.send(data) 52 client.send(err_data) 53 54 except ConnectionRefusedError: 55 client.close() 56 print('链接中断') 57 break

1 import socket 2 import struct 3 import json 4 5 client = socket.socket() 6 7 client.connect(('127.0.0.1', 8888)) 8 9 while True: 10 cmd = input('>>>:').strip().encode('utf-8') 11 if not cmd: 12 print('cmd命令不能为空') 13 continue 14 client.send(cmd) 15 16 # 接受额外信息长度 17 length = client.recv(4) 18 len_data = struct.unpack("i", length)[0] 19 #接受额外信息 20 t_json = client.recv(len_data) 21 json_dic = json.loads(t_json.decode('utf-8')) 22 print('执行时间为%s'%json_dic['time']) 23 data_size = json_dic['size'] 24 25 #接收真实数据 26 all_data = b'' 27 rcv_size = 0 28 29 while rcv_size < data_size: 30 data = client.recv(1024) 31 rcv_size += len(data) 32 all_data += data 33 34 print('接收长度为%s' % rcv_size) 35 print(all_data.decode('gbk'))