一、引言
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所支持的数据格式,按照指定的语言规则(传输协议)进行数据格式转换并且发送/接收即可。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)