我正在处理一个代码,其中有一个结构及其成员之一是一个动态数组(大小直到运行时才知道)。 我需要通过UDP连接发送此结构,并能够在另一端读取和处理数据。
我知道我可以使用指针和malloc定义动态数组,但不能通过UDP发送指针。而且我也在尝试避免序列化。
结构类似于这样,用户必须输入ID来定义消息类型以及数组中的消息。
struct foo
{
unsigned int ID;
unsigned int Num;
unsigned int size;
char arr[size]; //I know this is not acceptable in C, just typing to show my question.
};
是否存在另一种创建可以通过UDP套接字发送的动态数组的方法?以及在接收方上处理此问题的最佳方法是什么?
答案 0 :(得分:1)
通过UDP发送具有动态大小的结构没有什么特别的。通常,您只需要分配足够的内存,就像Bodo在他的回答中描述的那样。 另外,请查看GCC手册:Arrays of Length Zero和Arrays of Variable Length,希望对您有所帮助。并且不要忘记UDP消息有大小限制。
[...]我也在尝试避免序列化。
我经常看到人们避免编解码器,因为他们的目标是提高性能。最后,由于极性交换和打包问题,它们相反。 序列化是您的朋友,尤其是在与其他进程通信时。值得一读的是Rob Pike's article about byte-order
答案 1 :(得分:0)
您可以定义一个具有最小数组的结构,并为具有更大数组的结构分配内存。
以下代码示例无效的C,它不完整。通过网络发送到另一台计算机时,它也无法处理int
值的可能字节顺序或大小差异。
struct foo
{
unsigned int ID;
unsigned int Num;
unsigned int size;
char arr[1];
};
int size = 123;
int i;
int ret;
struct foo *ptr = malloc(offsetof(struct foo, arr) + size);
ptr->ID = 42;
ptr->Num = 99;
ptr->size = size;
for(i=0; i<ptr->size; i++)
{
ptr->arr[i] = data;
}
ret = sendto(sockfd, ptr, offsetof(struct foo, arr) + size, flags,
dest_addr, addrlen);
编译器不在乎您访问的数组索引大于结构声明中定义的数组索引。您必须检查代码中的索引,以避免内存访问错误。
接收者可以将recvfrom()
与MSG_PEEK
一起使用,并将报头的大小(offsetof(struct foo, arr)
)用作临时结构struct foo tmp;
,然后根据{{ 1}}字段,然后将结构的完整大小读取到动态分配的内存中。另请参见How to read UDP packet with variable length in C
或者为size
使用最大大小的固定缓冲区,然后将数据复制到动态分配的结构中。返回值recvfrom()
会告诉您所需的大小。
根据Matthias Simon答案中的建议进行编辑:
如果您的编译器支持零大小的数组,则可以对代码进行一些简化。
在结构定义中,您可以使用recvfrom()
代替char arr[0];
。这样可以在char arr[1];
,sizeof struct foo
和offsetof(struct foo, arr)
中将malloc()
与sendto()
一起使用recvfrom()
。