【问题标题】:How does the python socket.recv() method know that the end of the message has been reached?python socket.recv() 方法如何知道已经到达消息末尾?
【发布时间】:2016-12-29 14:58:03
【问题描述】:

假设我使用 1024 作为客户端套接字的缓冲区大小:

recv(1024)

假设服务器要发送给我的消息由 2024 个字节组成。 我的套接字只能接收 1024 个字节。其他 1000 字节发生了什么?

  1. recv 方法是否会等待一定的时间(比如 2 秒)以获取更多数据并在此时间跨度之后停止工作? (即如果剩下的数据在 3 秒后到达,socket 就不再接收数据了?)

  1. recv 方法在收到 1024 字节数据后会立即停止工作吗? (即其他 1000 个字节会被丢弃吗?)

如果 1.) 是正确的...有没有办法让我确定时间量,recv 数据应该在返回之前等待还是由系统确定? (即我可以告诉套接字在停止等待更多数据之前等待 5 秒吗?)

更新: 假设,我有以下代码:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((sys.argv[1], port))
    s.send('Hello, world')
    data = s.recv(1024)
    print("received: {}".format(data))
    s.close()

假设服务器发送的数据大小 > 1024 字节。我可以确定变量“数据”将包含所有数据(包括第 1024 个字节之外的数据)吗? 如果我不能确定这一点,我将如何更改代码,以便我始终可以确定变量“数据”将包含从服务器发送的所有数据(在一个或多个步骤中)?

【问题讨论】:

  • 您告诉计算机接收 1024 字节的数据,它确实如此。它并不关心一开始是否有更多数据要读取。
  • @ForceBru - recv 可以返回 1 到 1024 字节之间的任何内容(或 0,表示 recv 管道已被另一方关闭)。如果您要求 1024,但例如 44 立即可用,您将只得到 44。
  • @ForceBru - 你说它准确地接收了 1024 个字节,但它没有。我试图澄清这一点。
  • @ForceBru 你说“你告诉计算机接收 1024 字节的数据,它确实如此”。
  • @ForceBru - 引用:“你告诉计算机接收 1024 字节的数据,它确实如此。” 这不是真的。它可能接收不到 1024 个字节。更少不是“完全”。

标签: python sockets recv


【解决方案1】:

这取决于协议。某些协议(如 UDP)发送消息,并且每个 recv 仅返回 1 条消息。假设您专门讨论 TCP,则涉及多个因素。 TCP 是面向流的,由于当前未完成的发送/接收数据量、线路上丢失/重新排序的数据包、数据的延迟确认和 Nagle 算法(将一些小发送延迟几百毫秒)等原因,它的随着客户端和服务器之间的对话进行,行为可能会发生微妙的变化。

所有接收者都知道它正在获取字节流。它可以在任何 recv 上获得从 1 到完全请求的缓冲区大小的任何值。一侧的 send 调用和另一侧的 recv 调用之间没有一对一的关联。

如果您需要确定消息边界,则由更高级别的协议来解决。以 HTTP 为例。它以 \r\n 分隔的标头开始,然后计算客户端应期望接收的剩余字节数。客户端知道如何读取标头,因为 \r\n 然后确切地知道接下来有多少字节。 RESTful 协议的部分魅力在于它们是基于 HTTP 的,而且其他人已经发现了这些东西!

一些协议使用 NUL 来分隔消息。其他人可能有一个固定长度的二进制标头,其中包括即将到来的任何可变数据的计数。我喜欢zeromq,它在 TCP 之上有一个强大的消息传递系统。

有关接收的更多详细信息...

当你做recv(1024)时,有6种可能

  1. 没有接收数据。 recv 将等待直到有接收数据。您可以通过设置超时来更改它。

  2. 有部分接收数据。你会马上得到那部分。其余的要么被缓冲,要么尚未发送,您只需执行另一个 recv 以获得更多(并且适用相同的规则)。

  3. 有超过 1024 个字节可用。您将获得其中的 1024 个数据,其余数据被缓冲在内核中等待另一个接收。

  4. 另一端已关闭套接字。您将获得 0 字节的数据。 0 表示您永远不会在该套接字上获得更多数据。但是如果你一直要求数据,你会一直得到 0 个字节。

  5. 另一端已重置套接字。你会得到一个例外。

  6. 其他一些奇怪的事情发生了,你会得到一个例外。

【讨论】:

  • 我对你的回答的理解是这样的:在 TCP 层面,我无法确定 recv() 的行为(即它是否会在收到一堆数据后返回,或者是否会获取更多数据,但在 x 秒后停止等待)。即,决定何时停止等待/读取的策略只能在更高级别进行配置。 ……这个理解正确吗?
  • 是的,基本上就是这样。通常需要基于 TCP 的更高级别的协议来了解如何处理数据。
  • 也许值得知道的是,如果你使用 UDP(或 Unix 数据报)套接字,任何比你调用 recv() 时使用的缓冲区长的数据都将被丢弃。如前所述,TCP(或流)套接字将为下一次recv() 调用保留额外的内容。
猜你喜欢
  • 2015-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
相关资源
最近更新 更多