- 粘包:发送方发送两个字符串”hello”, ”world”,接收方却一次性接收到了”helloworld”
- 分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”
1 服务端
import socket
import struct
HOST = ''
PORT = 1234
# FIFO消息队列
dataBuffer = bytes()
# 自定义消息头的长度
headerSize = 12
# 定义数据包的个数
sn = 0
# 正文数据处理
def dataHandle(headPack, body):
global sn
sn += 1
print(f"第{sn}个数据包")
print(body.decode())
print("\n")
if __name__ == '__main__':
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if data:
# 把数据存入缓冲区,类似于push数据
dataBuffer += data
while True:
if len(dataBuffer) < headerSize:
print("数据包(%s Byte)小于消息头部长度,跳出小循环" % len(dataBuffer))
break
# 读取包头
# struct中!代表Network order,3I代表3个unsigned int数据
headPack = struct.unpack('!3I', dataBuffer[:headerSize])
bodySize = headPack[1]
# 分包情况处理,跳出函数继续接收数据
if len(dataBuffer) < headerSize+bodySize :
print("数据包(%s Byte)不完整(总共%s Byte),跳出小循环" % (len(dataBuffer), headerSize+bodySize))
break
# 读取消息正文的内容
body = dataBuffer[headerSize:headerSize+bodySize]
# 数据处理
dataHandle(headPack, body)
# 数据出列
dataBuffer = dataBuffer[headerSize+bodySize:] # 获取下一个数据包,类似于把数据pop出
2 客户端
import socket
import time
import struct
import json
host = "localhost"
port = 1234
ADDR = (host, port)
if __name__ == '__main__':
client = socket.socket()
client.connect(ADDR)
# 正常数据包定义
ver = 1
body = json.dumps(dict(hello="world"))
print(body)
cmd = 101
header = [ver, body.__len__(), cmd]
headPack = struct.pack("!3I", *header)
sendData1 = headPack+body.encode()
# 分包数据定义
ver = 2
body = json.dumps(dict(hello="world2"))
print(body)
cmd = 102
header = [ver, body.__len__(), cmd]
headPack = struct.pack("!3I", *header)
sendData2_1 = headPack+body[:2].encode()
sendData2_2 = body[2:].encode()
# 粘包数据定义
ver = 3
body1 = json.dumps(dict(hello="world3"))
print(body1)
cmd = 103
header = [ver, body1.__len__(), cmd]
headPack1 = struct.pack("!3I", *header)
ver = 4
body2 = json.dumps(dict(hello="world4"))
print(body2)
cmd = 104
header = [ver, body2.__len__(), cmd]
headPack2 = struct.pack("!3I", *header)
sendData3 = headPack1+body1.encode()+headPack2+body2.encode()
# 正常数据包
client.send(sendData1)
time.sleep(3)
# 分包测试
client.send(sendData2_1)
time.sleep(0.2)
client.send(sendData2_2)
time.sleep(3)
# 粘包测试
client.send(sendData3)
time.sleep(3)
client.close()