【问题标题】:Idiom for socket receive in PythonPython中套接字接收的成语
【发布时间】:2011-03-21 16:25:38
【问题描述】:

我有一些使用 C 语言中的 Berkeley 套接字 API 进行套接字编程的经验。通常,任何套接字编程都需要一种策略,使接收套接字知道它应该接收多少数据。这可以通过标题长度字段或分隔符来完成。一般来说,我更喜欢包含长度的标题字段。

当然,我们需要知道长度头域本身的大小,它只是一个固定的大小值,必须由发送者和接收者双方商定。在 C 中,这很容易实现,因为原生整数类型是固定大小的二进制格式,所以你可以这样说:

uint16_t bytes_to_receive;
recv(sock, &bytes_to_receive, sizeof(bytes_to_receive), 0);
bytes_to_receive = ntohs(bytes_to_receive);
// Now receive 'bytes_to_receive' bytes...

但是这种习惯用法是如何使用 Python 套接字完成的呢?在 Python 中,整数是对象,而腌制整数是可变长度的字节数组。所以我们不能使用腌制整数作为长度头字段,因为我们无法确定它的大小(以字节为单位)。

当然,我总是可以发送一个包含二进制整数的已知大小的字节数组,例如b'\x05\x00',以创建一个值为 5 的小端格式的 16 位二进制整数,但这似乎并不喜欢正确的方法。

那么,这在 Python 中通常是如何完成的呢?

【问题讨论】:

    标签: python c sockets


    【解决方案1】:

    您可以使用struct 模块将 Python 整数与字符串/字节数组相互转换。只需读取与类型标头大小相对应的字节数,然后使用struct 模块将其转换即可。 (注意:编码/解码时一定要使用正确的endian-flags)

    【讨论】:

      【解决方案2】:

      sys 模块提供了getsizeof() 函数,它以字节为单位返回对象的大小(使用对象__sizeof__ 方法)。如果您正在使用自定义对象,则需要仔细测试您的 __sizeof__ 实现,但听起来这对于标准类型应该可以正常工作。

      或者,您也可以将数据序列化为picklejson 并计算字符串中的字符数,尽管这可能会导致性能损失。

      使用任一方法,如果您要传输可变长度数据,请先传输大小,然后使用该值来确定要读取的数据量。

      其他说明:

      • 如果您还没有阅读过,您还需要阅读 sockets 的 api 文档。
      • 请注意,列表等复合类型需要额外的空间,因此:
      >>> 导入系统 >>> a = [1,3,4] >>> sys.getsizeof(a) 96 >>> l = 0 >>> for i in a: ... l += sys.getsizeof(i) ... >>> 打印 l 72 >>>

      【讨论】:

        【解决方案3】:

        ctypes module 可以为您在示例中使用的 C 类型 uint16 提供 sizeof()

        >>> import ctypes
        >>> ctypes.sizeof(ctypes.c_uint16)
        2
        

        【讨论】:

          最近更新 更多