一、问题描述
因为需要发送一条超过1024字节的消息,但是recv函数的缓冲区被设为1024字节(以太网的MTU为1500字节,不能设置得更大),所以需要循环接收缓冲区的消息并拼接。
total_data = b''
data = client.recv(1024)
while data:
# 将收到的数据拼接起来
total_data += data
data = client.recv(1024) # 程序会阻塞在这里,并等待另一端发送消息
上网看了两种解决方案,一是预先把消息的长度发送给服务端,另一个是双方商议一个消息结尾(比如消息末尾加上end)。后者感觉不太行,万一消息结尾刚好被截断,程序就进入了死循环,还可能会出现要发送的消息中出现end的情况。于是选用第一个方案。
二、解决方案
预先把要发送消息的长度发送给服务端,听起来很容易,其实是不太容易的,直接用send发送完长度再发消息,容易出现粘包问题,为发送的消息写一个头部还需要提取头部,非常麻烦。
后来想到密码学中模的概念,每次缓冲区提取1024个字节,然后把剩下的提取出来,那么,当剩下的消息长度小于1024,不就代表后面没有消息了?
三、实验结果
初始版本
# 客户端发送消息
client.sendall(message)
# 服务端接收消息
total_data = bytes()
while True:
# 将收到的数据拼接起来
data = self.client.recv(1024)
total_data += data
if len(data) < 1024:
break
最后成功打印出客户端发送的长消息。
但是评论区的网友@Python zzy提出了消息长度刚好是1024的倍数会阻塞的情况,所以针对这种情况进行了改进。
改进版本
# 客户端发送消息
if len(message) % 1024 == 0:
message = message + b' ' # 比如加上空格,根据自己实际需求更改
client.sendall(message)
服务端保持原样:
# 服务端接收消息
total_data = bytes()
while True:
# 将收到的数据拼接起来
data = self.client.recv(1024)
total_data += data
if len(data) < 1024:
break