下面是来自C的Struct,我正在尝试转换为Python, 并使用Socket发送结构
C:
struct CommandReq
{
char sMark[6]; //start flag\r\n*KW
short nPackLen; //packet length
short nFlag; //command ID 0x0002
int nGisIp; //GIS port
short nPort; //GIS Port
char sData[50]; //command string
char sEnd[2]; //end flag "\r\n"
};
//source code
CommandReq stResq;
memset(&stResq, 0, sizeof(stResq));
sprintf(stResq.sMark, "\r\n%s", "*KW");
stResq.nFlag = 0x0002;
stResq.nPackLen = sizeof(stResq);
stResq.nGisIp = 0;
stResq.nPort = 0;
strcpy(stResq.sData, "*KW,CC09C00001,015,080756,#");
strncpy(stResq.sEnd, "\r\n", 2);
我使用namedtuple创建了Python结构,并使用socket发送此结构。 但不幸的是失败了。
的Python:
from collections import namedtuple
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
在弄清楚之后,python 3.x必须添加字符串.encode(“ascii”)
format_ = "6shhih50s2s"
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
tuple_to_send = MyStruct(sMark="\r\n{}".format("*KW").encode("ascii"),
nPackLen=struct.calcsize(format_),
nFlag=0x0002,
nGisIp=0,
nPort=0,
sData= "*KW,NR09G05133,015,080756,#".encode("ascii"),
sEnd="\r\n".encode("ascii"))
string_to_send = struct.pack(format_, *tuple_to_send._asdict().values()
socket.sendto(string_to_send, self.client_address)
下面是数据包正在发送结构
format_ = "6shhih50s2s" //total bytes should be 68 bytes?
0d0a2a4b5700 //6 char \r\n*KW
4600 // packet length 70 bytes
0200 //command ID 0x0002,short 2 bytes
00000000 //GIS port is integer 4 bytes
0000 //GIS Port short 2 bytes
0000 //unknown??what is this?
2a4b572c4e5230394730353133332c3031352c3038303735362c230000000000000000000000000000000000000000000000 //sData[50] char 50 bytes
0d0a //sEnd 2 char,2 bytes
2个未知字节怎么来?
答案 0 :(得分:1)
namedtuple与c-struct无法真正比较。如果您习惯使用结构,可以查看struct
-module以将结构化信息转换为字符串。
通常,Pythonistas更喜欢使用pickle
-module进行序列化。
from collections import namedtuple
import pickle # or cPickle, it's faster
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
tuple_to_send = MyStruct(sMark="abcdef", nPackLen=...)
string_to_send = pickle.dumps(tuple_to_send)
有两种口味的泡菜,pickle
和cPickle
。后者更快,但仅在CPython(大多数程序员使用)中可用,而pickle也可用于Jython,IronPython,......
如果你想坚持使用struct(例如,因为另一方需要这种格式),你的格式字符串将是
format_ = "6shhih50s2s"
所以你可以这样做:
import struct
from collections import namedtuple
format_ = "6shhih50s2s"
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
tuple_to_send = MyStruct(sMark="\r\n{}".format("*KW"),
nPackLen=struct.calcsize(format_),
nFlag=0x0002,
nGisIp=0,
nPort=0,
sData= "*KW,NR09G05133,015,080756,#",
sEnd="\r\n")
string_to_send = struct.pack(format_, *tuple_to_send._asdict().values())
BTW:namedtuples是不可变的,即你不能做
tuple_to_send.sMark = "bcdefg"
改变一些财产。如果您需要此类行为,则必须创建一个类。
修改强>
对于Python 3,字符串处理已更改。必须执行从unicode到字节的转换,例如
import struct
from collections import namedtuple
format_ = "6shhih50s2s"
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
tuple_to_send = MyStruct(sMark="\r\n{}".format("*KW").encode("ascii"),
nPackLen=struct.calcsize(format_),
nFlag=0x0002,
nGisIp=0,
nPort=0,
sData= "*KW,NR09G05133,015,080756,#".encode("ascii"),
sEnd=b"\r\n")
string_to_send = struct.pack(format_, *tuple_to_send._asdict().values())