1.数据粘包处理思路

每次发送的消息时,都将消息划分为 头部(固定字节长度) 和 数据 两部分。例如:头部,用4个字节表示后面数据的长度。

  • 发送数据,先发送数据的长度,再发送数据(或拼接起来再发送)。
  • 接收数据,先读4个字节就可以知道自己这个数据包中的数据长度,再根据长度读取到数据。

对于头部需要一个数字并固定为4个字节,这个功能可以借助python的struct包来实现:

  1. import struct
  2. # ########### 数值转换为固定4个字节,四个字节的范围 -2147483648 <= number <= 2147483647 ###########
  3. v1 = struct.pack('i', 199)
  4. print(v1) # b'\xc7\x00\x00\x00'
  5. for item in v1:
  6. print(item, bin(item))
  7. # ########### 4个字节转换为数字 ###########
  8. v2 = struct.unpack('i', v1) # v1= b'\xc7\x00\x00\x00'
  9. 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()

  1. - 客户端
  2. ```python
  3. import socket
  4. import struct
  5. client = socket.socket()
  6. client.connect(('127.0.0.1', 8001))
  7. # 第一条数据
  8. data1 = 'alex正在吃'.encode('utf-8')
  9. header1 = struct.pack('i', len(data1))
  10. client.sendall(header1)
  11. client.sendall(data1)
  12. # 第二条数据
  13. data2 = '翔'.encode('utf-8')
  14. header2 = struct.pack('i', len(data2))
  15. client.sendall(header2)
  16. client.sendall(data2)
  17. client.close()