python之struct

来源:互联网 发布:胡适道德与规则 知乎 编辑:程序博客网 时间:2024/06/06 03:35

最近在写一个tcp的服务端,交互的报文是字节流。

在python中解析字节流,那就是必须用到struct包,但是在使用过程中发现一个问题。

那就是使用struct.pack的时候发现拼出来的字符串和自己想得到的不一样。

比如下面这段代码:

import struct
import binascii
import dis

print '5sI len is:',struct.calcsize('5sI')
req_msg = struct.pack('5si', "1234",5,)
print 'req_msg:',binascii.b2a_hex(req_msg)

我当初认为第一个打印的长度应该是5+4=9?但实际不然,先看下打印内容


结果是12,在原来的基础上增加了3位,那么req_msg也自然也不会是我们想得到的字符串,这是为什么呢?

1、难道5s超长,内存溢出了?不可能啊。但还是尝试的把长度改短试了下

print '3sI len is:',struct.calcsize('3sI')
req_msg = struct.pack('3sI', "1234",5)
print 'req_msg:',binascii.b2a_hex(req_msg)

结果

也不是自己想要的7位长度,而是加了1变成了8?  各种问问???????

2、我猜,后面的在5s后面I影响到了5s的判断,组成了一个新的类型sI类型,所以导致出错了,那我就尝试把I去掉;

print '3s len is:',struct.calcsize('3s')
req_msg = struct.pack('3s', "1234")
print 'req_msg:',binascii.b2a_hex(req_msg)

结果




果然,这回没有问题了。而且长度肯定是不会存在异常的情况。


那么为什么呢?加上I之后,就变了呢? 结果查资料,分析,终于分析清楚了。

python的struct实现是基于c语言的struct实现的,而struct结构体在开辟内存空间的时候,是有一个规则的。

struct的总长度必须是结果体内最大基本单元的整数倍,不够整数就补位凑成整数。

比如:5sI    实际是对应c语言里面的struct {char a[5]; int b};这样的结构,那么最大的基本单元长度是4,而2个值的总长度5+4=9,不是4的整数倍,需要+3位变成

           12位,这样解释就通了。

           3sI  也是一样的  3+4=7   需要补1位,变为8位。

           关于c语言struct内存分配可以参考此文章:

            http://blog.csdn.net/Thanksgining/article/details/42024977


那么如何解决这种:

            在struct.pack拼串的时候,采用网络字节序、大端、小端的模式

           

print '!5sI len is:',struct.calcsize('!5sI')
req_msg = struct.pack('!5sI', "1234",5)
print 'req_msg:',binascii.b2a_hex(req_msg)


print '>5sI len is:',struct.calcsize('>5sI')
req_msg = struct.pack('>5sI', "1234",5)
print 'req_msg:',binascii.b2a_hex(req_msg)