我有一个结构:
struct one
{
char name[10];
int age;
};
struct two
{
int X;
int Y;
};
现在我想发送这个结构,例如第一个'一个',第二个'两个'并从套接字接收。
但是,如果我不知道我发送了哪种结构(stuct'one'或'two'),怎么接收呢?
答案 0 :(得分:4)
您可以为您要发送的数据添加标识符:
enum StructID {
STRUCT_ONE,
STRUCT_TWO,
};
在发送数据之前发送。
Uint16 id;
struct one dataOne;
id = STRUCT_ONE;
send(&id, sizeof(id));
send(&dataOne, sizeof(dataOne));
在接收端:
char buffer[256];
unsigned nbRecv;
nbRecv = recv(buffer, sizeof(buffer));
if (nbRecv > sizeof(Uint16))
{
char * p = buffer;
Uint16 *pId = (Uint16*)p;
p += sizeof(*pId);
if (*pId == STRUCT_ONE)
{
struct one * pOne = (struct one *)p;
p += sizeof(*pOne);
if (nbRecv >= sizeof(*pId) + sizeof(*pOne))
{
// deal with pOne.
}
else
{
// Deal with too little data; pOne is incomplete....
}
}
else if (*pId == STRUCT_TWO)
{
struct two * pTwo = (struct two *)p;
p += sizeof(*pTwo);
if (nbRecv >= sizeof(*pId) + sizeof(*pTwo))
{
// deal with pOne.
}
else
{
// Deal with too little data; pTwo is incomplete....
}
}
else
{
// Error, unknown data.
}
}
else
{
// Deal with too little data....
}
基本上,您此时正在定义协议,而标识符只是一个非常简单的标题"存在以识别您的数据。像这样的许多协议也会发送数据的大小,以便你可以在下一个标识符/标题之前判断出有多少数据。
除整数之外的另一种常用方法是发送4个ASCII字符,因为当您查看原始数据(Wireshark,hexdump,调试器中的字节等)时它们很容易读取。对于你的例子,我建议:
const char STRUCT_ONE_FOURCC[4] = { 'O', 'N', 'E', ' ' };
const char STRUCT_ONE_FOURCC[4] = { 'T', 'W', 'O', ' ' };
(注意,他们不是说每个字符串因为它们不会被NULL终止。它们是固定大小的字符数组。)
注意:在上面的代码中,我遗漏了大多数错误检查和字节序交换(与网络字节顺序相对)。
另见:
答案 1 :(得分:0)
您需要执行序列化,添加标识符。一个(不那么)简单的解决方案是:
template<int index>
struct serializable {
static const int identifier = index;
}
struct A :
public serializable<1>
{
int a, b;
char * serialize() { char *buffer = new char[sizeof (A) + sizeof (int)]; memcpy(buffer, this, sizeof(A)); }
static A deserialize(const char *in) { return A{&in[sizeof(int)], &in[sizeof(int) * 2]}; }
}
答案 2 :(得分:0)
您应该定义一个将在通信中使用的协议,不要因为不同系统中的不同数据类型和内存对齐而发送struct。您可以使用xml,序列化您的结构并发送xml字符串。还要检查通过TCP实现通信协议的不同库。例如,您可以检查Apache Axis。对于手动序列化,您可以使用boost :: serialization并将结构转换为xml字符串。