python提供了一个struct模块来提供转换。下面就介绍这个模块中的几个方法。
struct.pack():
struct.pack用于将Python的值根据格式符,转换为字符串(因为Python中没有字节(Byte)类型,可以把这里的字符串理解为字节流,或字节数组)。其函数原型为:struct.pack(fmt, v1, v2, ...),参数fmt是格式字符串,关于格式字符串的相关信息下面有所介绍。v1, v2, ...表示要转换的python值。下面的例子将两个整数转换为字符串(字节流):
>>> import struct
>>> a=20
>>> b=400
>>> str=struct.pack('ii',a,b) #转换成字节流,虽然还是字符串,但是可以在网络上传输
>>> print len(str) #ii 表示两个int
8 #可以看到长度为8个字节,正好是两个int型数据的长度
>>> print str
#二进制是乱码
>>> print repr(str)
'\x14\x00\x00\x00\x90\x01\x00\x00' #其中十六进制的 0x00000014, 0x00001009分别表示20和400
>>>
struct.unpack():
我们接着上面的例子运行:
>>> a1,a2=struct.unpack('ii',str)
>>> print 'a1',a1
a1 20
>>> print 'a2=',a2
a2= 400
python 实现和 C的IP socket通信如何打包数据?
服务器端是C/C++写的,python用于客户端发送消息,进行通信。这种模式可以用于压力测试,方便修改协议。
问题:
1.python 对于组包和二进制的操作没有C语言那么方便,如何针对数据类型打包?
python作为方便的脚本语言,提供了很少的几种数据类型,和C语言不能一一对应。打通信包时,不能做到像C语言那样移动和操作指针。
2.对于变长的字符串变量如何打到python包中
struct中格式化字符串需指定长度,但如果字符串长度不是固定的,如何打包和解包呢?
解决办法: 用python 的struct来进行打包。struct提供pack,unpack,pack_into,unpack_from函数,提供与C语言对应的数据format。
3.二进制数据如何打包?
1. 格式化二进制数据
示例:
|
会将两个整形以二进制打到包中。程序执行结果:
'\x01\x00\x00\x00\x02\x00\x00\x00'
格式和C语言类型的对应关系:
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)其中 p是pascal 类型的字符串,s是c语言类型字符串。format中可以增加一个长度描述。如”6i”表示6个整形。”20s”表示20个字节长度的字符串,而“20c”表示20个字节。format还可以指定字节序。
Character Byte order Size Alignment @ native native native = native standard none < little-endian standard none > big-endian standard none ! network (= big-endian) standard none网络字节序一般用“!”打头。
2.给字符串变量打包
可以对格式化字符串再格式化,填写变量长度
示例
>>> a="test buf">>> leng=len(a)>>> fmt="i%ds"%leng>>> buf=struct.pack(fmt,1,a)
>>> print repr(buf)'\x01\x00\x00\x00test buf'
如果是单纯打包,stackoverflow给出一种方式,可以用于打变量字符串:
#给字符串变量打包,给出长度struct.pack("I%ds" % (len(s),), len(s), s)#解包def unpack_helper(self,fmt, data): size = struct.calcsize(fmt) return struct.unpack(fmt, data[:size]), data[size:]fmt_head="!6i"head,probuf = self.unpack_helper(fmt_head,buf)
3.打包二进制
二进制包可以直接将二进制坠在格式化数据后面,可以用字符串的方式处理。
>>> fmt1="!i">>> buf2=struct.pack(fmt1,2)+buf1>>> print repr(buf2)'\x00\x00\x00\x02\x01\x00\x00\x00\x02\x00\x00\x00'
4.实例 给一个二进制header后缀二进制数据
suffix是后缀的二进制或字符串,leng 是header中用于描述后缀长度的变量,type是cmdtype
def getheader(msgtype,leng,suffix): magic = 0 sn=0 ori_res=0 # mtype=msgtype param = 0 #mleng = leng fmt="!6i" buf = struct.pack(fmt,magic,sn,ori_res,msgtype,param,leng)+suffix
或者pack_into,可以pack到一个buf中
def getheader(msgtype,leng,suffix): magic = 0 sn=0 ori_res=0 # mtype=msgtype param = 0 #mleng = leng buf = create_string_buffer(24+leng) fmt = "!6i%ds"%leng print fmt struct.pack_into(fmt,buf,0,magic,sn,ori_res,msgtype,param,leng,suffix) #print repr(buf.raw) #for test #b = struct.unpack_from(fmt,buf) #print b return buf
总结:
可以用python 库struct 来完全对应C语言的二进制通信,解决跨语言通信问题