2

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 Answer 1

2

Take a look at the struct you're sending:

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

This does not contain instances of s_HEADER and s_OUTPUTDATA, but pointers to those structures. So you're not sending the data, but pointers.

Since pointer addresses are only meaningful to the process that created them, these pointers on the receiving side don't point to a valid memory location, so dereferencing those pointers leads to undefined behavior.

Rather than containing pointers, change the struct to contain the actual data:

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

Then you send, giving the size of the struct:

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

Something else you need to address is endianness and structure padding.

Some systems store integer types with the least significant byte (LSB) first, while others start with the most significant byte (MSB) first. The htonl and htons functions can convert 32 bit and 16 bit values respectively from the host byte order (either LSB or MSB) to network byte order (MSB), and the ntohl and ntohs perform the reverse of those two functions.

A struct may contain some amount of padding between elements or at the end. How that padding is laid out is implementation dependent. So the binary layout of a struct on one system may not be the same as on another system.

Dealing with padding can be addressed by sending each data field separately instead of whole structs so that the sent data is in a known format. Alternately, you can use this guide to structure packing to build your structs in such a way as to potentially eliminating padding or reducing it to a known amount at the end.

Sign up to request clarification or add additional context in comments.

4 Comments

thanks for ur fast reply. Wow, completely missed that. but now i get a compiling error when working with the pointer of both structs (cause they dont exist anymore). Do i need to change everything to instances?
@Frechdachs Yes, because the datatypes of the members have changed, you need to addressed how they're used. I.e. p->sHeader.i_head instead of p->sHeader->i_head.
ok, damn it. cause i have e.g a function with a pointer to the s_OUTPUTDATA struct as return and now i need to return the whole struct which is simply too heavy. or can i cast the pointer content to an instance?
@Frechdachs Depending on how the function is used, you can probably still use a pointer. Instead of returning one, pass one in as a parameter (as the address of a variable of that type) that the function would populate.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.