网络总是不可预测的。TCP会让很多这种随机行为消失。TCP做了一件很好的事情:它保证字节以相同的顺序到达。但是!它不能保证它们会以同样的方式被切碎。您不能简单地假设连接一端的每个send()都会在远端产生一个recv(),字节数完全相同。
当你说socket.recv(x)时,你是说“在从套接字读取x字节之前不要返回”。这称为“阻塞I/O”:您将阻塞(等待)直到您的请求被填满。如果协议中的每条消息都是1024字节,那么调用socket.recv(1024)将非常有效。但听起来不是这样的。如果您的消息是固定字节数,只需将该数字传递给socket.recv(),就完成了。
但是如果你的信息长度不同呢?您需要做的第一件事是:停止使用显式数字调用socket.recv()。更改此:data = self.request.recv(1024)
对此:data = self.request.recv()
意味着recv()在获得新数据时总是返回。
但现在你又遇到了一个新问题:你如何知道发件人何时向你发送了完整的邮件?答案是:你不需要。你必须将消息的长度作为协议的一个明确部分。最好的方法是:在每条消息前面加上一个长度前缀,可以是一个固定大小的整数(使用socket.ntohs()或socket.ntohl()转换为网络字节顺序,请!)或作为字符串后跟某个分隔符(如“123:”)。第二种方法通常效率较低,但在Python中更容易实现。
一旦将其添加到协议中,就需要更改代码来处理随时返回任意数量数据的recv()。下面是一个如何做到这一点的例子。我试着把它写成伪代码,或者用注释告诉你该怎么做,但不是很清楚。所以我用长度前缀作为以冒号结尾的数字字符串显式地写了它。给你:length = None
buffer = ""
while True:
data += self.request.recv()
if not data:
break
buffer += data
while True:
if length is None:
if ':' not in buffer:
break
# remove the length bytes from the front of buffer
# leave any remaining bytes in the buffer!
length_str, ignored, buffer = buffer.partition(':')
length = int(length_str)
if len(buffer) < length:
break
# split off the full message from the remaining bytes
# leave any remaining bytes in the buffer!
message = buffer[:length]
buffer = buffer[length:]
length = None
# PROCESS MESSAGE HERE