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

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

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

2.2 struct.unpack

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

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

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

2.3 struct.calcsize

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

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

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

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

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

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

Python 写的服务器端:

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

C 写的客户端:

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

struct 模块的更多相关文章

  1. 字节流与数据类型的相互转换---使用struct模块

    字节流与数据类型的相互转换---使用struct模块 http://blog.csdn.net/Sunboy_2050/article/details/5974029 Python是一门非常简洁的语言 ...

  2. Python学习——struct模块的pack、unpack示例

    he struct module includes functions for converting between strings of bytes and native Python data t ...

  3. c语言write与python的struct模块交互

    以下讲的都是用二进制形式打开文件.网上有很多struct模块的文章,下面是我做的小实验. 1.对于c里面的fwrite写入一个单字节,写的就是它的二进制.如3,写入文件就是二进制0x03,它并不是3的 ...

  4. python中struct模块及packet和unpacket

    转自:http://www.cnblogs.com/gala/archive/2011/09/22/2184801.html 我们知道python只定义了6种数据类型,字符串,整数,浮点数,列表,元组 ...

  5. 浅析Python中的struct模块

    最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概了解了,在这里做一下简单的总结. 了解c语言 ...

  6. 2、粘包现象(struct模块)

    昨天我们所做的套接字是有漏洞的,它会出现粘包现象,没有发现这个问题的我们今天会进行演示.今天也会稍微讲解一下基于udp的套接字. 一.基于udp的套接字 udp是无链接的,先启动哪一端都不会报错 ud ...

  7. Python struct模块

    有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体. struct模块中最重 ...

  8. python中的struct模块的学习

    由于TCP协议中的黏包现象的发生,对于最low的办法,每次发送之前让他睡一秒,然后在发送,可是这样真的太low了,而且太占用资源了. 黏包现象只发生在tcp协议中: 1.从表面上看,黏包问题主要是因为 ...

  9. python tcp黏包和struct模块解决方法,大文件传输方法及MD5校验

    一.TCP协议 粘包现象 和解决方案 黏包现象让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)执行远程命令的模块 需要用到模块subprocess sub ...

  10. 【转】浅析Python中的struct模块

    [转]浅析Python中的struct模块 最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概 ...

随机推荐

  1. idea中Maven-build lifecycle中下面标签详解

    原文链接:https://blog.csdn.net/mr_orange_klj/article/details/82153945 Maven是基于一个build lifecycle的中心概念,意味着 ...

  2. 文件下载:报错The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'

    前言:这篇文件下载的后台代码太繁琐,建议参考https://www.cnblogs.com/zwh0910/p/13745947.html 前端: <el-button type="p ...

  3. Git:分支管理

    代码中至少有一个分支,就是主分支master,默认都是在主分支上开发. 多分支 分支名: 版本库中必须唯一 不能以 - 开头 可以试用/,但不能以/结尾,被/分隔的名称不能以.开头 不能有连个连续的 ...

  4. PAT-1140(Look-and-say Sequence)字符串处理

    Look-and-say Sequence PAT-1140 #include<iostream> #include<cstring> #include<string&g ...

  5. CentOS安装libxml2报undefined reference to `gzopen64'

    主要是记录一下安装时候踩的坑 CentOS在make libxml2的时候,会报这个错误 ./.libs/libxml2.so: undefined reference to `gzopen64' c ...

  6. 2020年12月-第02阶段-前端基础-CSS Day03

    CSS Day03 盒子模型(CSS重点) css学习三大重点: css 盒子模型 . 浮动 . 定位 主题思路: 理解: 1.能说出盒子模型有那四部分组成 2.能说出内边距的作用以及对盒子的影响 3 ...

  7. C语言入门--初来乍到

    Hi,我是fish-studio,这是我写的第一篇博客,接下来我会以萌新的角度来与大家一起学习C语言,我也不是什么大佬,在我写的教程中会尽量详细的把我遇到的问题写出来,也会结合一些网上的文章进行编写, ...

  8. 浅谈Java的反射的原理

    Java的编译过程 谈及反射,不得不先了解一下,java的整个编译过程,整体的java编译过程可以参考 之前的一篇 一个java文件被执行的历程 这里我们只针对 对象这一层级来讨论,一个java文件, ...

  9. P1090 合并果子(JAVA语言)

    题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可 ...

  10. PTA 单链表分段逆转

    6-9 单链表分段逆转 (25 分)   给定一个带头结点的单链表和一个整数K,要求你将链表中的每K个结点做一次逆转.例如给定单链表 1→2→3→4→5→6 和 K=3,你需要将链表改造成 3→2→1 ...