【问题标题】:why does python socket library not include recvall() method like sendall()?为什么 python 套接字库不包含像 sendall() 这样的 recvall() 方法?
【发布时间】:2014-09-27 01:11:29
【问题描述】:

使用recv() 方法时,有时我们无法接收到我们想要的数据,就像使用send() 一样。但是我们可以使用 sendall() 来解决发送数据的问题,那么接收数据呢?为什么没有这样的 recvall() 方法?

【问题讨论】:

  • 在“接收所有”的上下文中,“所有”到底是什么意思?
  • @NPE 这意味着如果我写这样的东西:data = socket.recvall(1024),接收到的数据长度正好是 1024。而如果我使用 data = socket.recv(1024),有时接收到的数据小于 1024 字节。
  • 这在某些情况下确实很有用。不过,在您的代码中实现是微不足道的(在recv() 周围循环)。

标签: python sockets python-2.7


【解决方案1】:

send 具有recv 没有的额外信息:要发送多少数据。如果你有 100 个字节的数据要发送,sendall 可以客观地判断第一次调用send 发送的数据是否少于 100 个字节,并不断发送数据,直到发送完所有 100 个字节。

当您尝试读取 1024 个字节,但只返回 512 个字节时,您无法没有知道这是因为其他 512 个字节被延迟了,您应该尝试读取更多,或者是否一开始只有 512 个字节要读取。你永远不能说会有更多的数据要读取,这会使recvall 毫无意义。你能做的最多就是决定你愿意等待多长时间(超时)以及在放弃之前你愿意重试多少次。

您可能想知道为什么从文件读取和从套接字读取之间存在明显差异。对于文件,您可以从文件系统中获得有关文件中有多少数据的额外信息,因此您可以可靠地区分 EOF 和其他可能阻止您读取可用数据的信息。没有这样的套接字元数据来源。

【讨论】:

  • 如果您正在解析“类型、长度、值”协议,您确切地知道需要读取多少字节 - 首先足以读取类型和长度字段(其中将具有恒定的长度),然后是您知道读取标题的大小的值。任何类型的问题都意味着消息格式错误,因此您可以安全地中止连接。
  • 当然,如果您正在使用这样的协议。不过,这超出了socket 库的范围。
  • 除非您应该使用套接字库用于标准库 (socket.makefile('r').readline()) 中的类 ACSII 协议。愚蠢的是,没有二进制协议,您有办法知道要读取多少。
  • 而且我认为您并不欣赏我们尝试在 Python 中执行此操作的事实。你应该问自己的第一件事是“Python 如何解决我的问题”,而不是尝试第 n 次重新发明轮子。无论您是库还是应用程序开发人员。如果您正在编写基于 ASCII 的协议解析器,它确实为您提供了轮子,而不是二进制协议。
  • 我对您的回答有疑问,您在其中假设 先验 @flymike 无法知道对方将提供多少数据。这是一个糟糕的答案,我在其他 cmets 中解释了为什么,以及为什么提出的问题是完全有效的。
【解决方案2】:

因为recvall 从根本上令人困惑:您的假设是它会读取精确的 N 个字节,但根据名称,我会认为它会完全耗尽流。

一个完全耗尽流的操作是一个危险的 API,原因有很多,而且命名的模糊性使得它成为一个非常低效的 API。

【讨论】:

    【解决方案3】:

    没有根本原因不能将这样的函数作为标准库的一部分提供。其实已经有at least one attempt to add recvall()了。

    鉴于它可以很容易地实现为围绕recv() 的循环,我不认为这是一个重大遗漏。

    【讨论】:

    • 如果您自己在recv 周围的循环中实现它,那么您可以以适合您的方式处理它失败。弄清楚如果recv 失败,recvall 应该做什么是导致您链接到比目鱼的补丁的原因。
    • 根据我过去几年查看带有 [socket] 标签的 python 问题的经验,这是一个重大遗漏。
    • // 我不认为这是一个重大的遗漏 // 不过它确实让新手感到困惑。
    猜你喜欢
    • 2016-06-20
    • 2011-11-08
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多