1. Struct 简介

2. Struct 代码示例

2.1 struct.pack

2.2 struct.unpack

2.3 struct.calcsize

1. Struct 简介

当 python 需要通过网络与其他的平台进行交互的时候,必须考虑到将这些数据类型与其他平台或语言之间的类型进行互相转换问题。打个比方:C++ 写的客户端发送一个 int 型(4 字节)变量的数据到 python 写的服务器,python 接收到表示这个整数的 4 个字节数据,怎么解析成 python 认识的整数呢?python 的标准模块 struct 就用来解决这个问题。

格式符

在 python 手册中,给出了 C 语言中常用类型与 python 类型对应的格式符:

格式符

C语言类型

Python类型

x

pad byte

no value

c

char

string of length 1

b

signed char

integer

B

unsigned char

integer

?

_Bool

bool

h

short

integer

H

unsigned short

integer

i

int

integer

I

unsigned int

integer or long

l

long

integer

L

unsigned long

long

q

long long

long

Q

unsigned long long

long

f

float

float

d

double

float

s

char[]

string

p

char[]

string

P

void *

long

2. Struct 代码示例

2.1 struct.pack

struct.pack 用于将 python 值(各种数据类型),根据格式符转换为 bytes(字节)类型。

函数原型为:struct.pack(fmt, v1, v2, ...),参数 fmt 是格式字符串;v1, v2, ... 表示要转换的 python 数据。

示例 1:将两个整数转换为 bytes(字节)类型

格式符"i"表示转换为 int,"ii"表示有两个 int 变量。进行转换后的结果长度为 8 个字节(int 类型占用 4 个字节,两个 int 为 8 个字节),可以看到输出的结果是二进制数据。

 1 import struct
2
3 a = 20
4 b = 400
5
6 # 转换后的bytes_str为bytes(字节)类型,可以在网络上传输
7 bytes_str = struct.pack("ii", a, b) # 也可以用"2i"表示
8
9 print("length: ", len(bytes_str)) # 8
10 print(bytes_str) # b'\x14\x00\x00\x00\x90\x01\x00\x00'
11 print(type(bytes_str)) # <class 'bytes'>

示例 2:将字符串和整数转换为 bytes(字节)类型

 1 import struct
2
3 a = b"abc123"
4 b = "嘻哈".encode("utf-8")
5 c = 12
6
7 bytes_str = struct.pack("5s7si", a, b, c) # argument for 's' must be a bytes object
8 a1, a2, a3 = struct.unpack("5s7si", bytes_str)
9
10 print(a1, a2, a3) # b'abc12' b'\xe5\x98\xbb\xe5\x93\x88\x00' 12
11 # 注意:对于s,转换的多余长度会用\x00补齐

2.2 struct.unpack

struct.unpack 做的工作刚好与 struct.pack 相反,用于将字节类型的数据转换成 python 数据。

函数原型为:struct.unpack(fmt, string),返回的是一个元组。

 1 import struct
2
3 a, b = 20, 400
4
5 bytes_str = struct.pack("ii", a, b)
6 a1, a2 = struct.unpack("2i", bytes_str)
7 print(a1, a2) # 20 400
8
9 # 注意只unpack一个值时的取法
10 bytes_c = struct.pack("i", a)
11 c, = struct.unpack("i", bytes_c)
12 print(c) # 20
13 d = struct.unpack("i", bytes_c)
14 print(d) # (20,)

2.3 struct.calcsize

struct.calcsize 用于计算格式字符串所对应的结果的长度,如:struct.calcsize('ii') 返回 8。因为两个 int 类型所占用的长度是 8 个字节。

1 >>> struct.calcsize("19s") + struct.calcsize("i")
2 23
3 >>> struct.calcsize("i19s")
4 23
5 >>> struct.calcsize("19si")
6 24

问:为什么"19si"的结果不是 23 呢?

任何特定类型(字节、整数等)只能从其标准尺寸的倍数的偏移开始。

字节串 s 可以从任何偏移量开始,因为它的标准大小为 1,但是 32 位整数只能以 4 的倍数(它的大小)偏移量开始,例如 0、4、8、12 等,因此必须填充若干个字节以允许整数处于适当的偏移量。

示例:Python 写的服务器端与 C 写的客户端的通信

Python 写的服务器端:

 1 import socket, struct
2
3 s = socket.socket()
4 s.bind(('127.0.0.1', 8000))
5 s.listen(1)
6
7 try:
8 while True:
9 cli, addr = s.accept()
10 data = cli.recv(100)
11
12 print("recv %d bytes" % len(data))
13 a, b, c = struct.unpack('i10sh', data)
14 print(a, b, c)
15 # i表示int, 10s表示10个char类型, h表示short int
16 sdata = struct.pack('i10sh', 34, b"abcdefghi", 65)
17 cli.send(sdata)
18 finally:
19 s.close()

C 写的客户端:

 1 /* tcp_client.c */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <unistd.h>
10
11 typedef struct _data {
12 int a;
13 char b[10];
14 short c;
15 } Data;
16
17 int main()
18 {
19 int client_fd;
20 struct sockaddr_in server_addr;
21
22 server_addr.sin_family = AF_INET;
23 server_addr.sin_port = htons(8000);
24 server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
25 bzero(&(server_addr.sin_zero), 8);
26
27 client_fd = socket(AF_INET, SOCK_STREAM, 0);
28
29 connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
30
31 Data d;
32 memset(&d, 0, sizeof(d));
33 d.a = 3;
34 memcpy(&d.b, "hello", 5);
35 d.c = 6;
36 send(client_fd, &d, sizeof(d), 0);
37
38 char buf[200];
39 bzero(buf, 200);
40 recv(client_fd, buf, sizeof(buf), 0);
41
42 Data* p = (Data*)&buf;
43 printf("%d %s %d\n", p->a, p->b, p->c);
44
45 close(client_fd);
46
47 return 0;
48 }

最新文章

  1. MS SQL巡检系列&mdash;&mdash;检查重复索引
  2. canvas beginPath()
  3. 由项目中一个hash2int函数引发的思考
  4. Java 获取当前系统时间方法比较
  5. 通过SMATFORMS打印程序的参考模板
  6. 原生Android动作
  7. [原创作品]一个实用的js倒计时器 postby:zhutty.cnblogs.com
  8. C++内置类型对象之间的转换
  9. 功能间(两个form)数据交互的编程方法
  10. ionic2 跳转子页面隐藏底部导航栏
  11. 模板层(template)
  12. EventBus VS Spring Event
  13. Guava新增集合类型-Multiset
  14. 从 RegExp 构造器看 JS 字符串转义设计
  15. go语言模版编程
  16. 6.Django扩展
  17. 数据规整化:pandas 求合并数据集(交集并集等)
  18. e665. 在图像中过滤三元色
  19. laya3d 文件格式
  20. 把windows电脑变成路由器使用

热门文章

  1. 构建Docker私有仓库
  2. Python Linux 命令行执行脚本输出重定向print到日志文件
  3. IO、NIO、BIO的区别
  4. 将VMware虚拟机最小化到托盘栏
  5. 【译】Rust宏:教程与示例(一)
  6. Ch1-What is DAX?
  7. `vi`——终端中的编辑器
  8. SQL SERVER跨数据库服务,联表进行查询
  9. 微服务分布式事务之LCN、TCC
  10. effective解读-第一条 静态工厂创建对象代替构造器