我正在开展一个项目,我需要通过TCP / IP协议与设备进行通信。 设备发送大量数据,我不知何故想要解析为某些对象/结构。
Datapackage示例(在TCP缓冲区[]中):
[64] [1] [78] [244] [77] [189] [249] [149] hcurrent
[64] [1] [78] [247] [89] [95] [104] [85] htarget
[0] [0] [0] [0] [0] [0] [0] [0] qcurrent
[188] [220] [97] [3] [66] [62] [0] [0] kcurrent
[66] [0] [102] [103] [66] [99][153] [154] mcurrent
[253] [191] [246] [74] [170] [216] [242] [29] fmode
[102] [191] [246] [74] [178] [44] [92] [72] tmil
[137] mode
现在这个包裹框架被标识为:
double hcurrent
double htarget
double qcurrent
float kcurrent
float mcurrent
float fmode
float tmil
unsigned char mode
我的想法是,我不知何故可以将数据直接解析为具有与上述相同结构的结构。 当然,有必要确定一些关键值来确定它是哪种数据。
如何做到这一点?
由于我正在为iOS设备编码,因此它必须是客观的C或C(++)。
EDIT(测试将数据报的每个部分复制到struct中的方法):
小Java实现,我尝试读取前4个字节[0] [0] [1] [5]
:
byte[] read = new byte[4];
int length = 0;
while (length < read.length) {
len = iStream.read(read, len, read.length);
}
int ByteLength = (int)unsignedIntToLong(read);
ByteLength = ByteLength-5;
state = 1; // Continue and work with next data.
位操作方法:
public long unsignedIntToLong(byte[] b)
{
long l = 0;
l |= b[0] & 0xFF;
l <<= 8;
l |= b[1] & 0xFF;
l <<= 8;
l |= b[2] & 0xFF;
l <<= 8;
l |= b[3] & 0xFF;
return l;
}
所以我获取前面提到的前4个字节,它决定了特定的东西,最后找到了465
的长度。我的计划是重复此过程以及所接收数据的所有其他部分。
答案 0 :(得分:4)
你将遇到的最大问题是结构不能以完全连续的形式存储数据,它们会对齐数据acording to word boundaries
这意味着你不能简单地定义一个结构,然后如果缓冲区不包含一个开头的结构,则将缓冲区[]强制转换为它。相反,您可能需要做的是声明一个结构,然后使用apointer偏移量在缓冲区[]中一次一个字段地记忆缓冲区[]的每个部分。
如果这种方法过于繁琐,通常可以关闭结构对齐,以便结构可以表示完全打包的数据。 MSVC允许使用#pragma pack来执行此操作。但是,这种方法会减慢对结构的内存访问速度。
编辑:这是一个示例,它显示了如何使用模板函数从缓冲区读取任何类型,然后将偏移更新到该缓冲区。您可以使用此方法将任意数量的类型安全地逐个解析为结构:
// We want to copy raw data to this structure
// but the short will cause it to be unaligned
struct _parsed_structure
{
int a;
int b;
short c;
int d;
} parsed_structure;
template<typename T>
void read_and_update_offset (int & offset, char * buffer, T & var)
{
T * pInt = (T*)(buffer + offset);
var = *pInt;
offset += sizeof(T);
};
int _tmain(int argc, _TCHAR* argv[])
{
// Here's a buffer which we know contains ints and shorts, we could just cast it to our structure
// but this will cause errors because the structure will not be aligned properly.
char buffer[] = { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0 };
// Read the first int from the buffer into the structure
int offset = 0;
read_and_update_offset(offset, buffer, parsed_structure.a);
read_and_update_offset(offset, buffer, parsed_structure.b);
read_and_update_offset(offset, buffer, parsed_structure.c);
read_and_update_offset(offset, buffer, parsed_structure.d);
// Print the values
std::cout <<
parsed_structure.a << " " <<
parsed_structure.b << " " <<
parsed_structure.c << " " <<
parsed_structure.d << " " << std::endl;
// Look the size of our structure is different than the size of our buffer due to alignment
std::cout <<
"sizeof(buffer)" << "==" << sizeof(buffer) << " " <<
"sizeof(parsed_structure)" << "==" << sizeof(parsed_structure) << std::endl;
return 0;
}
答案 1 :(得分:2)
通常的方法是编写方法nextInt
,nextDouble
等,它们将从流中读取字节(以正确的“endian”顺序)并返回指定类型的值,将指针或索引更新为数组。这比尝试内联转换更易于管理,并且可以非常高效。 (您可以使用C ++与Objective-C的方法来提高效率。)