在C中通过UDP发送结构化动态数组

时间:2019-01-23 14:35:42

标签: c arrays dynamic udp

我正在处理一个代码,其中有一个结构及其成员之一是一个动态数组(大小直到运行时才知道)。 我需要通过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套接字发送的动态数组的方法?以及在接收方上处理此问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

通过UDP发送具有动态大小的结构没有什么特别的。通常,您只需要分配足够的内存,就像Bodo在他的回答中描述的那样。 另外,请查看GCC手册:Arrays of Length ZeroArrays 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 foooffsetof(struct foo, arr)中将malloc()sendto()一起使用recvfrom()