【问题标题】:How can I get a variable containing a byte sequence of several fields (unicode character + 32 bits integer + unicode string)如何获取包含多个字段的字节序列的变量(unicode 字符 + 32 位整数 + unicode 字符串)
【发布时间】:2019-08-07 10:45:02
【问题描述】:

我想得到一个包含几个字段的字节序列的变量(它们稍后将通过套接字传输)。

字节序列将包括以下三个字段:

  • 字符 SOH(ANSI 代码 0x01)
  • 32位整数
  • Unicode 字符串“Straße”

我试过了:

# -*- coding: UTF-8 -*-

message = b''

soh = u'\0001'
a = 1143
c = u'Straße'

message = message + soh + a + c

print(type(message))

但我明白了:

TypeError: can't concat str to bytes

我也不确定soh = u'\0001' 是定义 SOH 字符的正确方法。

我正在使用 Python 3.7

【问题讨论】:

    标签: python unicode byte python-unicode bytestream


    【解决方案1】:

    通过套接字连接传输的二进制数据最好使用struct 模块进行组合。

    struct模块提供了pack函数来创建数据结构。您需要提供一个format string 来描述正在打包的数据。值得研究格式字符串文档,以确保数据在接收端按预期解包。

    >>> soh = b'\x01'
    >>> a = 1143
    >>> c = u'Straße'
    
    >>> import struct
    >>> pattern = 'ci7s' # 1 byte, 1 int, 1 bytestring of length 7
    >>> packed = struct.pack(pattern, soh, a, c.encode('utf-8'))
    >>> packed
    b'\x01\x00\x00\x00w\x04\x00\x00Stra\xc3\x9fe'
    

    该模块提供了一个解包函数来反向打包:

    >>> soh_, a_, c_ = struct.unpack(pattern, packed)
    >>> soh_
    b'\x01'
    >>> a
    1143
    >>> a_
    1143
    >>> c_.decode('utf-8')
    'Straße'
    

    【讨论】:

    • 实用又有趣。我认为要传输的数据在字段数量、字符串长度等方面是可变的是相关的(在我的问题中,我只是将其缩小到一个具体示例)。所以我想在 unicode 字符串的长度之前加上长度,以便接收者可以解码消息。因此,客户端和服务器之间不会共享特定的模式。我想知道在那种情况下 struct.pack 是否与字段结构清晰时一样有用。我得到的另一个问题是使用 struct.pack 时整数是 32 位还是 64 位。
    • 每种类型的大小在格式字符串文档中给出 - 一个 int 大小为 4 个字节,除非指定了本机(平台相关)大小。如果您的消息始终采用 byte:int:bytes 形式,则可以根据消息的大小计算模式。如果您的消息更复杂,那么您将不得不提出自己的方案(或考虑第三方解决方案,如协议缓冲区,如果开销是值得的)。
    • 感谢您的澄清。由于消息的自定义和不确定性,我不会使用 struct.pack/struct.unpack。虽然我不知道这个包,但我认为它们对这类任务很有用。我最后会尝试一下 .to_bytes() 和 .encode()
    【解决方案2】:

    因为 a 是一个 int,所以你不能将它与 str 连接起来。 您应该做的是尝试在所有 soh、a 和 c 上使用 .encode(),然后将它们连接到消息(.encode 使类型从 str 变为 bytes)

    (在 python 3.x 中,unicode 类型不再存在(它与 str 相同)因此您必须使用 str 或 bytes)

    【讨论】:

    • 您能否详细说明.encode() 应使用哪些参数?谢谢。
    • 整数没有.encode方法,但是.to_bytes可以在Python 3.7中使用
    • 你必须做这样的事情。 a=a.encode() (记得在使用encode之前将a转换为字符串)
    • 如前所述,a 是整数,不能“编码”。并将其转换为字符串并不是它的本意。问题中明确指定整数需要作为 32 位字节整数表示形式包含在字节流中。有关完整答案,请参阅随附的答案,包括整数的 .encode('utf-8') 和 .to_bytes。
    【解决方案3】:

    以防万一它对其他人有帮助,我终于做到了:

    message = soh.encode('utf-8') + a.to_bytes(4, 'big') + c.encode('utf-8')
    

    struct.pack 是一个非常有趣的解决方案,但我没有设法将整数强制为 32 位,并且在我的特定格式中,字段结构事先不知道(因此需要一种在客户端和服务器之间共享它的机制反正)。

    因此,我将 .to_bytes 与 .encode 混合用于 unicode 字符串。

    【讨论】:

      猜你喜欢
      • 2021-07-31
      • 2020-12-19
      • 1970-01-01
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 2019-01-29
      • 2011-03-31
      相关资源
      最近更新 更多