最近在写一个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.youkuaiyun.com/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)