python解析C/C++结构体二进制数据

一、引言

socket为数据通信中必不可少的一部分,常用的有TCP数据传输协议和UDP数据传输协议。(具体的socket详情这里不赘述)。

不论是TCP还是UDP,凡是涉及到数据传输,都需要进行数据内容解析。而很多时候为了数据传输的有效性,一般都会制定协议,通过特定的协议进行数据通信。统一语言的通信相对比较简单,而跨语言通信就比较复杂。

本文站在巨人的肩膀上,借鉴各位大神的经验和自己处理问题的心得,主要就是介绍python和C++跨语言进行数据通信,以及数据通信过程中需要制定的协议和相关的协议解析方式。

二、struct包概述

用python处理socket的二进制数据时就需要用到struct包,struct包主要包括calcsize, pack, unpack几个函数,可以用来处理C/C++的结构体数据结构。

pack(fmt, v1, v2, …) 按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)

unpack(fmt, string) 按照给定的格式(fmt)解析字节流string,返回解析出来的tuple

calcsize(fmt) 计算给定的格式(fmt)占用多少字节的内存

struct中支持的数据格式:

Format C Type Python 字节
x pad byte(填充) no value
c char string of length 1 1
b signed char int 1
B unsigned char int 1
? _Bool bool 1
h short int 2
H unsigned short int 2
i int int 4
I unsigned int int 4
l long int 4
L unsigned long long 4
q long long long 8
Q unsigned long long long 8
f float float 4
d double float8 8
s char[] string
p char[] string
P void * long

为了同c中的结构体交换数据,还要考虑有的c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下:

Character Byte order Size & alignment
@ native native
= native standard
< little-endian standard
> big-endian standard
! network(=bid-endian) standard

注:网络通信默认大端模式,不需要特殊指定。

三、包头解析

在团队开发的时候,存在多语言开发,如处理一下C++结构体:

struct Header
{
    int flag;
    char[4] tag;
    int aWidth;
    unsigned int version;
    unsigned int count;
} aHead;

本质上来讲,结构体作为一种数据结构,在python中同样适用。只是python没有指针,想要解析结构体数据结构时使用struct.unpack即可。

ss = socket.recv(1024)
# i为int型,4s为4字节长度的字符串,2I为无符号int型;
flag, tag, width, version, count = struct.unpack('i4si2I', s)

多数帖子指出需要指定数据解析顺序,如网络数据'!4si2I',而根据本人实际测试,解析网络端数据无需指定解析顺序,即不需要<, >,即'4si2I'即可。

四、发送数据

Python给C++发送数据只需要将上述操作反向操作即可。

如发送flag, tag, width, version, count 给C++服务器,只需要将所有数据pack为二进制数据流发送即可。

flag = 2 # int
tag  = 'send' # str
width = 333  # int
version = 1.3.0 # unsigned int
count = 65535 # unsigned int

ss = struct.pack('i4si2I', flag, tag, width, version, count)
socket.send(ss)

一言以蔽之,可用struct对各种类型的数据打包转为二进制数据流。如:

a = 11
byte_a = struct.pack('i', a) # int型pack
get_a = struct.unpack('i', byte_a) # 反操作,转为int型

因此,只需要按照(二)struct概述所示的struct所支持的数据格式,按照指定的语言规则(传输协议)进行数据格式转换并且发送/接收即可。

你可能感兴趣的:(python,c++,数据结构)