套接字编程 Python:如何确保收到整个消息?

6 python sockets tcp

我正在使用 python 3.x 和 socket 模块。服务器在 ipv4 地址上运行并使用 tcp。我阅读了一些关于如何发送和接收数据的教程。为了让服务器或客户端确保发送了整个消息,您可以简单地检查发送的数据量是否等于消息的大小:

def mysend(self, msg):
    totalsent = 0
    while totalsent < MSGLEN:
        sent = self.sock.send(msg[totalsent:])
        if sent == 0:
            raise RuntimeError("socket connection broken")
        totalsent = totalsent + sent
Run Code Online (Sandbox Code Playgroud)

来源:https : //docs.python.org/3/howto/sockets.html#socket-howto

并且为了让客户端确保已收到整个响应,本教程建议在响应的开头添加响应的大小。

我的问题:

  1. 如何确保我收到消息的第一部分指示消息的大小(假设我的消息包含 1000 个字符,我需要四个字符来指示大小)?
  2. 为什么我不能在消息的请求处添加一个指定的符号,如“<”和“>”,以便我知道它的开始和结束位置?

编辑:

  1. 当我使用时sock.recv(1024),我的消息只有 500 到 1000 个字符的大小,这不能确保我收到所有消息吗?

Jam*_*olk 5

首先,要发送不需要循环的所有字节,因为 python 套接字提供了一个简单的方法:socket.sendall().

现在回答你的问题:

  1. 是的,即使只接收 4 个字节,您也应该有一个接收循环来调用recv()套接字,直到读取 4 个字节。

  2. 如果您能保证此类字符不会出现在消息本身中,可以。但是,您仍然需要搜索您读入的每个字符以获取魔术定界符,因此它似乎不如简单地在消息正文前加上一个长度。

  3. 当您调用recv(n)它时,只能保证最多返回n 个字节,而不是正好返回n 个字节。

以下是三种不同的recvall()比较方法:

def recvall(sock, size):
    received_chunks = []
    buf_size = 4096
    remaining = size
    while remaining > 0:
        received = sock.recv(min(remaining, buf_size))
        if not received:
            raise Exception('unexpected EOF')
        received_chunks.append(received)
        remaining -= len(received)
    return b''.join(received_chunks)
Run Code Online (Sandbox Code Playgroud)

和更短的

def recvall2(sock, size):
    return sock.recv(size, socket.MSG_WAITALL)
Run Code Online (Sandbox Code Playgroud)

最后是另一个版本,它比第一个短一点,但缺少一些功能:

def recvall3(sock, size):
    result = b''
    remaining = size
    while remaining > 0:
        data = sock.recv(remaining)
        result += data
        remaining -= len(data)
    return result
Run Code Online (Sandbox Code Playgroud)

第二个很好而且很短,但它依赖于一个套接字选项socket.MSG_WAITALL,我不相信它保证在每个平台上都存在。第一个和第三个应该在任何地方都有效。我还没有真正对任何基准进行比较和对比。