• Python之struct模块


    面对网络协议,在组包拆包时,python提供了struct模块,它可以帮助我们在python值和C语言的结构体之间相互转换,下面一起来了解struct的具体用法。

    假设,我们的网络协议为消息id(unsigned short类型)及消息payload(unsigned int类型)组成,那么该如何进行组包拆包呢?如下例所示:

    import struct
    
    # 组包, 其中msg_id为0x1002、msg_payload为0x10070008
    packet = struct.pack('>HI', 0x1002, 0x10070008)
    print("packet: %s" % packet)
    # 拆包
    msg_id, msg_payload = struct.unpack_from('>HI', packet)
    print("msg_id: %s , msg_payload: %s" % (hex(msg_id), hex(msg_payload)))

     运行结果:

    packet: b'x10x02x10x07x00x08'
    msg_id: 0x1002 , msg_payload: 0x10070008

    上述例子中,我们用到了pack(format, v1, v2, ...)函数组包及unpack(format, buffer)函数拆包,它们指定的消息格式为'>HI',即以大端字节序排列的unsigned short+unsigned int数据。

    关于字节顺序的符号,官方定义如下:

    关于格式类型的符号,官方定义如下:

     为了方便我们计算format的长度,比如上例中'>HI'的长度,struct提供了calcsize(format)函数供我们调用,如下例所示:

    import struct
    
    fmt_len = struct.calcsize('>HI')
    print("格式长度: %s" % fmt_len)

    运行结果:

    格式长度: 6

    下面,我们进一步来了解pack_into(format, buffer, offset, v1, v2, ...)函数unpack_from(format, buffer, offset=0)函数,它们在组包拆包时,可以指定所需的偏移量,这让组包拆包变得更加灵活。本文第一个例子中,网络协议为固定长度,但是更多时候,网络协议是可变长度的。假设,网络协议由消息id(unsigned short类型)、消息size(unsigned int类型)及可变长度的消息payload(若干个unsigned int类型)组成,那么该如何操作呢?下例将为大家解答。

    import struct
    import ctypes
    
    def load_packet(msg_id, msg_size, msg_payload):
        packet = ctypes.create_string_buffer(msg_size)
        struct.pack_into('>HI', packet, 0, msg_id, msg_size)
        struct.pack_into('>%dH' % (int(msg_size-6)/2), packet, 6, *msg_payload)
        return packet
    
    def unload_packet(packet):
        msg_id, msg_size = struct.unpack_from('>HI', packet, 0)
        msg_payload = struct.unpack_from('>%dH' % (int(msg_size-6)/2), packet, 6)
        return msg_id, msg_size, msg_payload
    
    if __name__ == '__main__':
        packet = load_packet(0x1002, 12, (0x1003, 0x1004, 0x1005))
        print("packet: %s" % packet.raw)
        msg_id, msg_size, msg_payload = unload_packet(packet)
        print(hex(msg_id), msg_size, [hex(item) for item in msg_payload])

    运行结果:

    packet: b'x10x02x00x00x00x0cx10x03x10x04x10x05'
    0x1002 12 ['0x1003', '0x1004', '0x1005']

    参考资料

    • https://docs.python.org/zh-cn/3/library/struct.html

    作者:酌三巡

    感谢阅读,如需转载请注明出处!

  • 相关阅读:
    浅拷贝与深拷贝的实现方式、区别;deepcopy如果你来设计,如何实现(一)
    可变与不可变类型(一)
    查看虚拟机版本
    无法应用原保存的显示器配置
    uname -a输出内容分析
    Python 模块
    Python 函数(三)
    Python 函数(二)
    Python 函数(一)
    5-26 单词长度
  • 原文地址:https://www.cnblogs.com/zhuosanxun/p/15105256.html
Copyright © 2020-2023  润新知