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