Python 和 C++ 套接字转换数据包数据

1 投票
2 回答
1806 浏览
提问于 2025-04-15 21:35

首先,我想说明一下我的目标:我们实验室里有两个用C语言写的程序。我正在为它们开发一个双向的代理服务器(也就是可以处理数据的服务器)。我想用Python来写这个代理服务器。需要说明的是,我对这两个程序几乎一无所知,只知道数据包的定义文件。

现在:假设其中一个C++程序的数据包定义是这样的:

unsigned char Packet[0x32]; // Packet[Length]
int z=0;

Packet[0]=0x00;     // Spare
Packet[1]=0x32;     // Length
Packet[2]=0x01;     // Source
Packet[3]=0x02;     // Destination
Packet[4]=0x01;     // ID
Packet[5]=0x00;     // Spare
for(z=0;z<=24;z+=8)
{
    Packet[9-z/8]=((int)(720000+armcontrolpacket->dof0_rot*1000)/(int)pow((double)2,(double)z));
    Packet[13-z/8]=((int)(720000+armcontrolpacket->dof0_speed*1000)/(int)pow((double)2,(double)z));
    Packet[17-z/8]=((int)(720000+armcontrolpacket->dof1_rot*1000)/(int)pow((double)2,(double)z));
    Packet[21-z/8]=((int)(720000+armcontrolpacket->dof1_speed*1000)/(int)pow((double)2,(double)z));
    Packet[25-z/8]=((int)(720000+armcontrolpacket->dof2_rot*1000)/(int)pow((double)2,(double)z));
    Packet[29-z/8]=((int)(720000+armcontrolpacket->dof2_speed*1000)/(int)pow((double)2,(double)z));
    Packet[33-z/8]=((int)(720000+armcontrolpacket->dof3_rot*1000)/(int)pow((double)2,(double)z));
    Packet[37-z/8]=((int)(720000+armcontrolpacket->dof3_speed*1000)/(int)pow((double)2,(double)z));
    Packet[41-z/8]=((int)(720000+armcontrolpacket->dof4_rot*1000)/(int)pow((double)2,(double)z));
    Packet[45-z/8]=((int)(720000+armcontrolpacket->dof4_speed*1000)/(int)pow((double)2,(double)z));
    Packet[49-z/8]=((int)armcontrolpacket->timestamp/(int)pow(2.0,(double)z));
}
if(SendPacket(sock,(char*)&Packet,sizeof(Packet)))
    return 1;
return 0;

那么,接收这些数据、把它们转换成Python能读懂的格式、处理这些数据并把它们发送给接收方,最简单的方法是什么呢?

2 个回答

3

看看这个 struct模块,特别是里面的打包(pack)和解包(unpack)函数。它们可以通过格式字符串来工作,这样你就可以指定你想要写入或读取的数据类型,以及你想使用的字节顺序和对齐方式。

4

你可以通过在正确连接的套接字上调用 .recv 来接收数据包的50个字节(如果TCP数据包被拆分了,可能需要多次调用,所以要检查接收到的字节数,直到你手上正好有50个字节为止;-)。

接下来,理解C语言的代码会让人感到困惑。将 int(每个大约4个字节)赋值给 Packet[9]Packet[13] 等等,给人的感觉是想要一次设置4个字节到 Packet 中,但实际上并不是这样:每次赋值只设置数据包中的一个字节,这个字节来自于赋值右边的 int 的最低位字节。不过,这些字节实际上是 (int)(720000+armcontrolpacket->dof0_rot*1000) 这样的计算结果的字节。

那么,数据包最后的44个字节应该被理解为11个4字节的整数(是有符号的还是无符号的?)还是44个独立的值呢?我猜是前者,然后进行处理...:

import struct
f = '>x4bx11i'
values = struct.unpack(f, packet)

格式 f 表示:大端格式,包含4个无符号字节值,中间夹着两个被忽略的“备用”字节,以及11个4字节的有符号整数。最终的元组 values 会有15个值:四个单字节(在你的例子中是50, 1, 2, 1),然后是11个有符号整数。你可以使用相同的格式字符串将修改后的元组打包回一个50字节的数据包中以便重新发送。

由于你在数据包中明确放置了长度,可能不同的数据包长度会不同(尽管这与C语言示例中的固定长度声明不兼容),在这种情况下,你需要在接收和解包时更加准确;不过这些细节依赖于你没有提供的信息,所以我就不再猜了;-)。

撰写回答