• 粘包:发送方发送两个字符串”hello”, ”world”,接收方却一次性接收到了”helloworld”
  • 分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”

image.png

1 服务端

  1. import socket
  2. import struct
  3. HOST = ''
  4. PORT = 1234
  5. # FIFO消息队列
  6. dataBuffer = bytes()
  7. # 自定义消息头的长度
  8. headerSize = 12
  9. # 定义数据包的个数
  10. sn = 0
  11. # 正文数据处理
  12. def dataHandle(headPack, body):
  13. global sn
  14. sn += 1
  15. print(f"第{sn}个数据包")
  16. print(body.decode())
  17. print("\n")
  18. if __name__ == '__main__':
  19. with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  20. s.bind((HOST, PORT))
  21. s.listen(1)
  22. conn, addr = s.accept()
  23. with conn:
  24. print('Connected by', addr)
  25. while True:
  26. data = conn.recv(1024)
  27. if data:
  28. # 把数据存入缓冲区,类似于push数据
  29. dataBuffer += data
  30. while True:
  31. if len(dataBuffer) < headerSize:
  32. print("数据包(%s Byte)小于消息头部长度,跳出小循环" % len(dataBuffer))
  33. break
  34. # 读取包头
  35. # struct中!代表Network order,3I代表3个unsigned int数据
  36. headPack = struct.unpack('!3I', dataBuffer[:headerSize])
  37. bodySize = headPack[1]
  38. # 分包情况处理,跳出函数继续接收数据
  39. if len(dataBuffer) < headerSize+bodySize :
  40. print("数据包(%s Byte)不完整(总共%s Byte),跳出小循环" % (len(dataBuffer), headerSize+bodySize))
  41. break
  42. # 读取消息正文的内容
  43. body = dataBuffer[headerSize:headerSize+bodySize]
  44. # 数据处理
  45. dataHandle(headPack, body)
  46. # 数据出列
  47. dataBuffer = dataBuffer[headerSize+bodySize:] # 获取下一个数据包,类似于把数据pop出

2 客户端

  1. import socket
  2. import time
  3. import struct
  4. import json
  5. host = "localhost"
  6. port = 1234
  7. ADDR = (host, port)
  8. if __name__ == '__main__':
  9. client = socket.socket()
  10. client.connect(ADDR)
  11. # 正常数据包定义
  12. ver = 1
  13. body = json.dumps(dict(hello="world"))
  14. print(body)
  15. cmd = 101
  16. header = [ver, body.__len__(), cmd]
  17. headPack = struct.pack("!3I", *header)
  18. sendData1 = headPack+body.encode()
  19. # 分包数据定义
  20. ver = 2
  21. body = json.dumps(dict(hello="world2"))
  22. print(body)
  23. cmd = 102
  24. header = [ver, body.__len__(), cmd]
  25. headPack = struct.pack("!3I", *header)
  26. sendData2_1 = headPack+body[:2].encode()
  27. sendData2_2 = body[2:].encode()
  28. # 粘包数据定义
  29. ver = 3
  30. body1 = json.dumps(dict(hello="world3"))
  31. print(body1)
  32. cmd = 103
  33. header = [ver, body1.__len__(), cmd]
  34. headPack1 = struct.pack("!3I", *header)
  35. ver = 4
  36. body2 = json.dumps(dict(hello="world4"))
  37. print(body2)
  38. cmd = 104
  39. header = [ver, body2.__len__(), cmd]
  40. headPack2 = struct.pack("!3I", *header)
  41. sendData3 = headPack1+body1.encode()+headPack2+body2.encode()
  42. # 正常数据包
  43. client.send(sendData1)
  44. time.sleep(3)
  45. # 分包测试
  46. client.send(sendData2_1)
  47. time.sleep(0.2)
  48. client.send(sendData2_2)
  49. time.sleep(3)
  50. # 粘包测试
  51. client.send(sendData3)
  52. time.sleep(3)
  53. client.close()