0

0

如何使用Python解析UDP传输的C语言嵌套结构体数组

DDD

DDD

发布时间:2025-11-20 11:31:15

|

477人浏览过

|

来源于php中文网

原创

如何使用python解析udp传输的c语言嵌套结构体数组

本教程旨在解决C语言嵌套结构体通过UDP传输到Python时,因指针序列化问题导致的解析困难。文章将深入探讨两种解决方案:一是利用`ctypes`模块进行分步解析和动态构建内部数组,二是采用纯Python类结合`struct`模块实现高效的数据反序列化,帮助开发者准确处理跨语言结构体数据。

1. 理解C语言结构体与指针的传输挑战

当C语言中包含指针的结构体通过网络(如UDP)传输时,直接使用memcpy复制整个结构体内存内容到缓冲区并发送,会遇到一个核心问题:只复制了指针变量本身的值(即内存地址),而没有复制指针所指向的实际数据。例如,一个MyStruct包含MyInnerStruct *InnerStruct字段,memcpy(&testStruct, buffer, sizeof(MyStruct))只会将testStruct在C程序内存中的地址值复制到缓冲区,而不是InnerStruct数组的实际内容。

在Python端,如果尝试使用ctypes将接收到的字节流直接解析为一个包含指针的结构体,那么该指针字段将包含一个在Python进程内存空间中无效的C程序内存地址。任何尝试解引用或访问该地址的操作都将失败或导致不可预测的行为。

因此,正确的做法是,C端在发送数据时,需要将主结构体的标量字段和内部数组的所有元素序列化成一个连续的字节流。Python端再根据这个序列化规则进行反序列化

立即学习Python免费学习笔记(深入)”;

2. Python ctypes分步解析与动态构建内部数组

这种方法利用ctypes来定义C结构体的Python对应物,并通过struct模块手动解析字节流,然后动态构建内部数组。

GitHub Copilot
GitHub Copilot

GitHub AI编程工具,实时编程建议

下载

2.1 C端数据序列化(概念模拟)

假设C端已经将数据序列化为以下字节流格式: 主结构体字段1 (int) | 主结构体字段2 (float) | 内部结构体元素1 (int, float) | 内部结构体元素2 (int, float) | ...

以下Python代码模拟了C端发送这种序列化数据的方式:

import struct
import socket

# 模拟C端发送的数据:
# field1=4 (int), field2=3.5 (float)
# 接着是4个MyInnerStruct元素:
# (1, 1.25), (2, 2.5), (3, 2.75), (4, 3.00)
# '

2.2 Python ctypes接收端实现

在Python端,我们需要定义ctypes.Structure来匹配C语言结构体的布局。

import socket
import struct
import ctypes as ct

# 定义内部结构体
class MyInnerStruct(ct.Structure):
    _fields_ = (('field4', ct.c_int),
                ('field5', ct.c_float))

    def __repr__(self):
        return f'({self.field4}, {self.field5})'

# 定义主结构体
class MyStruct(ct.Structure):
    _fields_ = (('field1', ct.c_int),
                ('field2', ct.c_float),
                ('field3', ct.POINTER(MyInnerStruct))) # 注意这里是POINTER

    def __repr__(self):
        # 访问field3时,需要确保它已被正确赋值为一个ctypes数组
        # 否则尝试list(self.field3[:self.field1])可能会失败
        inner_data = []
        if self.field3: # 检查指针是否有效
            for i in range(self.field1):
                inner_data.append(self.field3[i])
        return f'MyStruct(field1={self.field1}, field2={self.field2}, field3={inner_data})'

# UDP接收设置
sock = socket.socket(type=socket.SOCK_DGRAM)
sock.bind(('', 5000))
print("等待接收UDP数据...")

# 接收数据
data, addr = sock.recvfrom(40960) # 接收足够大的缓冲区

# 1. 解析主结构体的标量字段
# '

2.3 注意事项

  • 字节序(Endianness):struct.pack和struct.unpack_from中的格式字符串(如''表示大端序。C端和Python端的字节序必须一致。
  • 结构体对齐:ctypes通常会尝试模拟C语言的默认结构体对齐规则。如果C代码使用了特定的#pragma pack或其他对齐指令,Python ctypes也需要通过_pack_ = N来指定相同的对齐方式,以确保内存布局一致。在本例中,由于只使用了基本类型,默认对齐通常不会导致问题。
  • 内存管理:ctypes动态创建的数组在Python中由Python的垃圾回收机制管理。当received_struct或inner_array不再被引用时,它们占用的内存会被释放。

3. 纯Python类结合struct模块进行反序列化

对于不需要将Python对象传回C语言或与C库进行复杂交互的场景,完全放弃ctypes,使用纯Python类结合struct模块进行数据解析,通常会更简洁、更“Pythonic”,且易于理解和维护。

3.1 纯Python类定义与解析

import socket
import struct

# 定义纯Python的内部结构体类
class MyInnerStruct:
    _format = '

3.2 优点与适用场景

  • 简洁性:代码更简洁,避免了ctypes的复杂性(如指针、内存地址、类型映射等)。
  • Pythonic:更符合Python的编程习惯,直接操作Python对象。
  • 灵活性:数据解析逻辑完全由Python控制,可以更容易地处理更复杂或变化的数据格式。
  • 适用场景:当主要目的是将接收到的二进制数据转换为Python对象进行后续处理,而不需要与C语言进行直接内存交互时,此方法是更优的选择。

4. 总结与选择建议

处理C语言嵌套结构体通过UDP传输到Python的问题,关键在于理解C语言指针的本质以及数据的正确序列化与反序列化。

  1. C端发送:必须将所有相关数据(主结构体标量字段和所有内部数组元素)序列化成一个连续的字节流进行发送,而不是仅仅memcpy主结构体(如果它包含指针)。
  2. Python接收
    • ctypes分步解析:适用于需要将Python对象传回C语言、与C库深度交互,或者需要精确模拟C语言内存布局的场景。它提供了对C类型和内存的细粒度控制,但代码相对复杂。
    • 纯Python类反序列化:适用于大多数仅仅需要解析数据并转换为Python对象进行后续处理的场景。它更简洁、更Pythonic,通常更容易开发和维护。

在选择哪种方法时,请根据你的具体需求权衡复杂性、性能和与C语言交互的深度。对于大多数数据解析任务,纯Python类结合struct模块的方法通常是更推荐的选择。无论哪种方法,务必确保C端和Python端的字节序和数据类型定义(包括对齐)保持一致。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

401

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

619

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

354

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

259

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

603

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

530

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

645

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

603

2023.09.22

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号