1.数据粘包处理思路
每次发送的消息时,都将消息划分为 头部(固定字节长度) 和 数据 两部分。例如:头部,用4个字节表示后面数据的长度。
- 发送数据,先发送数据的长度,再发送数据(或拼接起来再发送)。
- 接收数据,先读4个字节就可以知道自己这个数据包中的数据长度,再根据长度读取到数据。
对于头部需要一个数字并固定为4个字节,这个功能可以借助python的struct包来实现:
import struct# ########### 数值转换为固定4个字节,四个字节的范围 -2147483648 <= number <= 2147483647 ###########v1 = struct.pack('i', 199)print(v1) # b'\xc7\x00\x00\x00'for item in v1:print(item, bin(item))# ########### 4个字节转换为数字 ###########v2 = struct.unpack('i', v1) # v1= b'\xc7\x00\x00\x00'print(v2) # (199,)
2.示例代码
- 服务端 ```python import socket import struct
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((‘127.0.0.1’, 8001)) sock.listen(5) conn, addr = sock.accept()
固定读取4字节
header1 = conn.recv(4) data_length1 = struct.unpack(‘i’, header1)[0] # 数据字节长度 21 has_recv_len = 0 data1 = b”” while True: length = data_length1 - has_recv_len if length > 1024: lth = 1024 else: lth = length chunk = conn.recv(lth) # 可能一次收不完,自己可以计算长度再次使用recv收取,指导收完为止。 1024*8 = 8196 data1 += chunk has_recv_len += len(chunk) if has_recv_len == data_length1: break print(data1.decode(‘utf-8’))
固定读取4字节
header2 = conn.recv(4) data_length2 = struct.unpack(‘i’, header2)[0] # 数据字节长度 data2 = conn.recv(data_length2) # 长度 print(data2.decode(‘utf-8’))
conn.close() sock.close()
- 客户端```pythonimport socketimport structclient = socket.socket()client.connect(('127.0.0.1', 8001))# 第一条数据data1 = 'alex正在吃'.encode('utf-8')header1 = struct.pack('i', len(data1))client.sendall(header1)client.sendall(data1)# 第二条数据data2 = '翔'.encode('utf-8')header2 = struct.pack('i', len(data2))client.sendall(header2)client.sendall(data2)client.close()
