C: Send nested Struct over TCP socket

时间:2016-12-09 13:08:39

标签: c sockets struct tcp malloc

Although this might be a duplicate post, I wanted to make sure how it works in my specific code.

What I wanna achieve?

Sending and receiving a struct over TCP/IP connection.

What I have so far?

Sender

initialize structs:

typedef struct soutputdata {
    unsigned long long ull_date;
    unsigned int    ui_ixl;
    unsigned int    ui_type;
    unsigned int    ui_index;
    char c_values[64][2];
    int i_valueid;
} s_OUTPUTDATA;

typedef struct sheader {
    int i_head;
} s_HEADER;

typedef struct soutdata {
    s_HEADER *sHeader;
    s_OUTPUTDATA *sDATAout;
} s_OUTDATA;

I now want to send an s_OUTDATA struct to a connected TCP client.

allocate memory (is this correct?):

s_OUTDATA *poutData = malloc(sizeof(s_OUTDATA));
poutData->sDATAout = malloc(sizeof(s_OUTPUTDATA));
poutData->sHeader = malloc(sizeof(s_HEADER));  

Sending the struct (how can i get the correct size of the whole s_OUTDATA struct?):

if ((send(sendSocket, poutData, 1024, 0)) == -1) {
        fprintf(errlog, "%.3f error: %s(): Failure Sending Message!\n", gettime(), __func__);
        close(sendSocket);
    }

Receiver

initialize structs:

typedef struct soutputdata {
    unsigned long long ull_date;
    unsigned int    ui_ixl;
    unsigned int    ui_type;
    unsigned int    ui_index;
    char c_values[64][2];
    int i_valueid;
} s_OUTPUTDATA;

typedef struct sheader {
    int i_head;
} s_HEADER;

typedef struct soutdata {
    s_HEADER *sHeader;
    s_OUTPUTDATA *sDATAout;
} s_OUTDATA;

allocate memory (is this correct?):

s_OUTDATA *p = malloc(sizeof(s_OUTDATA));
poutData->sDATAout = malloc(sizeof(s_OUTPUTDATA));
poutData->sHeader = malloc(sizeof(s_HEADER));  

Receiving the struct:

if ((num = recv(newSocket, p, 1024,0)) == -1) {
   perror("recv");
   exit(1);
}
else if (num == 0) {
   printf("Connection closed\n");
}

What is the problem?

When trying to work with the received data I get a segmentation fault.

printf("ui_index: %d\n", p->sDATAout->ui_index);

What am I missing?

I presume I have done sth wrong with the memory allocation but I am not sure what and how to solve it.

1 个答案:

答案 0 :(得分:1)

看看你发送的结构:

typedef struct soutdata {
    s_HEADER *sHeader;
    s_OUTPUTDATA *sDATAout;
} s_OUTDATA;

这不包含s_HEADERs_OUTPUTDATA实例,但指针包含这些结构。所以你不是发送数据,而是指针。

由于指针地址仅对创建它们的进程有意义,因此接收端的这些指针不指向有效的内存位置,因此取消引用这些指针会导致undefined behavior

不是包含指针,而是更改结构以包含实际数据:

typedef struct soutdata {
    s_HEADER sHeader;
    s_OUTPUTDATA sDATAout;
} s_OUTDATA;

然后发送,给出结构的大小:

send(sendSocket, p, sizeof(s_OUTDATA), 0)

您需要解决的其他问题是 endianness 结构填充

某些系统首先存储具有最低有效字节(LSB)的整数类型,而其他系统首先以最高有效字节(MSB)开始。 htonlhtons函数可以分别将32位和16位值从主机字节顺序(LSB或MSB)转换为网络字节顺序(MSB),以及ntohl和{ {1}}执行这两个函数的反向。

ntohs可能在元素之间或末尾包含一些填充量。如何布局填充是依赖于实现的。因此,一个系统上struct的二进制布局可能与另一个系统上的二进制布局不同。

处理填充可以通过分别发送每个数据字段而不是整个结构来解决,以便发送的数据采用已知格式。或者,您可以使用this guide to structure packing来构建结构,以便可能在最后消除填充或将其减少到已知量。