python提供了丰富的内置类型:比如字符串,整数,浮点数,列表,元组,字典,但是没有提供类似C语言的结构体类型,如果我们用python来实现客户端,用C来是实现服务器的话,需要用python来实现C的结构体,并且用UDP或者TCP传输。
python中的struct模块专门用来处理python的值和C的类型结构之间的转换,此模块执行的Python Python字符串表示的值和C的结构之间的转换。这可以用来处理的二进制数据存储在文件或网络连接,以及其他来源。
struct模块主要的方法有三种pack、unpack、calcsize:
struct.pack(fmt,v1,v2,.....) 将v1,v2等参数的值进行包装,包装的方法由fmt指定,被包装的参数必须严格符合fmt,最后返回字符串。
struct.unpack(fmt,string) 返回一个由解包数据(string)得到的一个元组(tuple)。
struct.calcsize(fmt),用来计算fmt格式所描述的结构的大小,也等于len(string)。
下面来介绍一下fmt(格式字符串格式):默认情况下,C类型的代表在机器的原生格式和字节顺序,如果必要的(按C编译器所使用的规则)跳过填充字节,正确对齐。此外,格式字符串的第一个字符,可以用来表明字节顺序,大小和压缩数据的对齐,根据下表:(默认情况是不加,实际上是按照@要求表示字节顺序以及字节,对齐)
Character
Byte order
Size
Alignment
@
native
native
native
=
native
standard
none
<
little-endian
standard
none
>
big-endian
standard
none
!
network (= big-endian)
standard
none
格式字符串除了上表的第一个字符外,还支持一下格式:
Format
C Type
Python type
Standard size
Notes
x
pad byte
no value
c
char
string of length 1
1
b
signed char
integer
1
(3)
B
unsigned char
integer
1
(3)
?
_Bool
bool
1
(1)
h
short
integer
2
(3)
H
unsigned short
integer
2
(3)
i
int
integer
4
(3)
I
unsigned int
integer
4
(3)
l
long
integer
4
(3)
L
unsigned long
integer
4
(3)
q
long long
integer
8
(2), (3)
Q
unsigned long long
integer
8
(2), (3)
f
float
float
4
(4)
d
double
float
8
(4)
s
char[]
string
p
char[]
string
P
void *
integer
(5), (3)
例子:直接使用library上的例子
>>>from struct import *
>>>pack('hhl', 1, 2, 3) 包装
'x00x01x00x02x00x00x00x03'
>>>unpack('hhl', 'x00x01x00x02x00x00x00x03') 解包
(1, 2, 3)
>>>calcsize('hhl')
8
最后来讲一下关键的问题:如何使用python来模拟C的结构体?
首先来看C的结构体如下面的形式:
struct info
{
int age;
float score;
char name1[3];
};
typedef struct my_data
{
char name[10];
struct info test;
} MY_DATA;
如果用python来进行包装的话,可以使用下面的形式:
name = "sleetdrop"
age = 28
score = 1000
name1="aes"
info = struct.pack("10sif3s", name,age, score, name1)
最后看看用python写的客户端,用C写的服务器,用UDP传输信息。
python代码:(ip地址和端口号根据自己需要更改)
import socket, struct
serviceip = "10.0.0.28"
port = 3000
name = "sleetdrop"
age = 28
score = 1000
name1="aes"
info = struct.pack("10sif3s", name,age, score, name1)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(info, (serviceip, port))
C的代码:
#include #include #include #include #include #include #include #include struct info
{
int age;
float score;
char name1[3];
};
typedef struct my_data
{
char name[10];
struct info test;
} MY_DATA;
void dg_echo(int, struct sockaddr *, socklen_t);
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in svraddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&svraddr, sizeof(svraddr));
svraddr.sin_family = AF_INET;
svraddr.sin_addr.s_addr = htonl(INADDR_ANY);
svraddr.sin_port = htons(3000);
bind(sockfd, (struct sockaddr *) &svraddr, sizeof(svraddr));
dg_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));
}
void
dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
MY_DATA mydata;
bzero(&mydata, sizeof(MY_DATA));
for( ; ; ) {
len = clilen;
n = recvfrom(sockfd, &mydata, sizeof(MY_DATA), 0, pcliaddr, &len);
printf("Name:%stAge:%dtScore:%fttest:%sn", mydata.name, mydata.test.age, mydata.test.score,mydata.test.name1);
}}