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. 格式化二進位制資料
示例:
import struct
fmt="ii"
buf = struct.pack(fmt,1,2)
print repr(buf)
會將兩個整形以二進位制打到包中。程式執行結果:
'x01x00x00x00x02x00x00x00'
格式和C語言型別的對應關係:
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還可以指定位元組序。
@ | 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)
'x01x00x00x00test 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)
'x00x00x00x02x01x00x00x00x02x00x00x00'
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語言的二進位制通訊,解決跨語言通訊問題
參考:
如非註明轉載, 均為原創. 本站遵循知識共享CC協議,轉載請註明來源