You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中解析IPv4报文头部并填充至自定义类实例

问题描述

我有一段如下所示的C语言代码:

struct iphdr{
#if __BYTE_ORDER == __LITTLE_ENDIAN
  unsigned int ihl:               4;
  unsigned int version:           4;
#elif __BYTE_ORDER == __BIG_ENDIAN
  unsigned int version:           4;
  unsigned int ihl:               4;
#else
  #error "Please fix <bits/endian.h>"
#endif
  uint8_t tos;
  uint16_t tot_len;
  uint16_t id;
  uint16_t frag_off;
  uint8_t ttl;
  uint8_t protocol;
  uint16_t check;
  uint32_t saddr;
  uint32_t daddr;

};
...
...
...
unsigned char * ip_header_bytes = "\x45\x00\x00\xf8\xb8\xa7\x00\x40\x06\x81\x80\xac\x10\x44\x03\x22\x78\xed\x4c";
struct iphdr * ipdata = (struct iphdr *)ip_header_bytes;

通过这段代码,我可以直接将字节数据强转为结构体指针,访问ipdata中的各个成员。现在我在Python中定义了一个与iphdr结构类似的类,且拥有与ip_header_bytes相同的字节数据,请问如何将该字节数据填充到该类的新实例中?

解决方案

Python没有原生的结构体位域语法,需要借助struct模块解析字节数据,手动处理位域拆分后,再映射到自定义类的实例上。以下是两种常用实现方式:

方法1:手动解析+实例赋值

先定义对应类,再通过struct.unpack解析字节,处理位域后赋值给类实例:

import struct

class IpHdr:
    def __init__(self, version, ihl, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr):
        self.version = version
        self.ihl = ihl
        self.tos = tos
        self.tot_len = tot_len
        self.id = id
        self.frag_off = frag_off
        self.ttl = ttl
        self.protocol = protocol
        self.check = check
        self.saddr = saddr
        self.daddr = daddr

# 目标字节数据(注意转为bytes类型)
ip_header_bytes = b"\x45\x00\x00\xf8\xb8\xa7\x00\x40\x06\x81\x80\xac\x10\x44\x03\x22\x78\xed\x4c"

# 按IP头部的大端字节序解包:第一个字节包含version和ihl,后续依次匹配C结构体类型
unpacked_data = struct.unpack(">B B H H H B B H I I", ip_header_bytes)
first_byte = unpacked_data[0]

# 拆分位域:大端序下第一个字节高4位是version,低4位是ihl
version = (first_byte >> 4) & 0x0F
ihl = first_byte & 0x0F

# 创建类实例并传入解析后的数据
ipdata = IpHdr(version, ihl, *unpacked_data[1:])

# 验证示例
print(ipdata.version)  # 输出4
print(ipdata.ihl)     # 输出5

方法2:类内部封装解析逻辑

把字节解析逻辑封装为类方法,更符合面向对象的使用习惯:

import struct

class IpHdr:
    def __init__(self, version, ihl, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr):
        self.version = version
        self.ihl = ihl
        self.tos = tos
        self.tot_len = tot_len
        self.id = id
        self.frag_off = frag_off
        self.ttl = ttl
        self.protocol = protocol
        self.check = check
        self.saddr = saddr
        self.daddr = daddr
    
    @classmethod
    def from_bytes(cls, byte_data):
        # 按大端序解包字节数据
        unpacked = struct.unpack(">B B H H H B B H I I", byte_data)
        first_byte = unpacked[0]
        # 拆分位域
        version = (first_byte >> 4) & 0x0F
        ihl = first_byte & 0x0F
        # 创建并返回类实例
        return cls(version, ihl, *unpacked[1:])

# 使用示例
ip_header_bytes = b"\x45\x00\x00\xf8\xb8\xa7\x00\x40\x06\x81\x80\xac\x10\x44\x03\x22\x78\xed\x4c"
ipdata = IpHdr.from_bytes(ip_header_bytes)

# 访问成员示例
print(ipdata.tot_len)  # 输出248(对应0x00f8)
print(ipdata.saddr)    # 输出3232243715(对应0xac104403)

关键注意事项

  • 字节序匹配:IP头部采用网络字节序(大端),所以struct.unpack使用>前缀;如果处理的是小端环境的非网络数据,要替换为<前缀。
  • 位域手动处理:Python没有原生位域支持,必须通过位移和掩码操作拆分第一个字节的高低4位,对应C结构体中的version和ihl。
  • 类型严格对应:struct格式符要与C结构体类型一一匹配:
    • C的uint8_t对应B
    • uint16_t对应H
    • uint32_t对应I

内容的提问来源于stack exchange,提问作者raging-loon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 10:18:34