0

I want to pass structure over a socket in C. I read about it here:

Passing a structure through Sockets in C

but mine problem is that I have inside of a structure array of integers, and I don't know how can I serialize and deserialize it, any advice?

struct packet{
    int id;
    char buffer[512];
    int array[4];
}

Serialize function , it is working but array of integers is missing

size_t encode_pack(packet pack, char *buf){

    size_t pack_len;
    unsigned char *pt = buf;
    *pt++ = (pack.id  >> 24) & 255 ;
    *pt++ = (pack.id  >> 16)& 255;
    *pt++ = (pack.id >> 8) & 255;
    *pt++ = (pack.id & 255);

    strcpy(pt,pack.buffer);
    pt += strlen(pack.buffer)+1;
    pack_len = sizeof(pack.id) + strlen(pack.buffer); 

    return pack_len;

}
Community
  • 1
  • 1
user3852803
  • 154
  • 1
  • 2
  • 11
  • 2
    If you don't care about byte order (for example if the socket refers to the local machine) `struct packet pack; res=write ( fd, &pack, sizeof pack);` , or equivalent, should do the trick – wildplasser Aug 13 '14 at 13:37
  • I have updated my question with the example code – user3852803 Aug 13 '14 at 14:05

2 Answers2

3

You can send like this:

struct packet p;
int socket;
// Todo: Get socket, initialize/populate p
int temp=hton(p.id);
send(socket,&temp,sizeof(temp),0);
send(socket,p.buffer,sizeof(p.buffer),0);
for (size_t i=0;i<4;++i) {
    temp=hton(p.array[i]);
    send(socket,&temp,sizeof(temp),0);
}
// Todo: Check send calls to make sure they succeed

And you can receive like this:

struct packet p;
int socket;
// Todo: Get socket
int temp;
recv(socket,&temp,sizeof(temp),0);
p.id=ntoh(temp);
recv(socket,p.buffer,sizeof(p.buffer),0);
for (size_t i=0;i<4;++i) {
    recv(socket,&temp,sizeof(temp),0);
    p.array[i]=ntoh(temp);
}
// Todo: Check return value of recv calls to make sure data actually received

hton and ntoh refer to a family of functions. You must choose the functions appropriate for your datatype. See here.

  • At first glance, this seems unnecessarily complex. However, this solves the issues of both differences in struct layout *and* endianness. +1 – Drew McGowen Aug 13 '14 at 13:53
  • Also, might be worth pointing out that `hton` and `ntoh` *probably* refer to the family of functions - the actual functions themselves have a `s` or `l` prefix. – Drew McGowen Aug 13 '14 at 13:54
  • I have edited the answer to include a note about `hton` and `ntoh`, along with a link to documentation. – Robert Allan Hennigan Leahy Aug 13 '14 at 13:56
  • I don't want to send separately every member of a structure and to receive them separately so this solution is not acceptable for me – user3852803 Aug 13 '14 at 13:57
  • Unfortunately that's how it has to be. Due to the existence of [padding](http://en.wikipedia.org/wiki/Data_padding) there's liable to be garbage between the members of the struct, and the struct is liable to be laid out differently in memory on different machines. You could go into the realm of compiler extensions and try and [pack](https://gcc.gnu.org/onlinedocs/gcc/Structure-Packing-Pragmas.html) the struct, but that should be considered harmful/avoided due to the fact it isn't portable, and isn't standard C. – Robert Allan Hennigan Leahy Aug 13 '14 at 14:00
  • Even if you do get all the alignment/padding issues worked out, there's still [endianness](http://en.wikipedia.org/wiki/Endianness), which is liable to be different between different machines. – Robert Allan Hennigan Leahy Aug 13 '14 at 14:02
  • It is not true, I have managed to send two members together in the structure but without array of integers. I have updated my question with the example code so you can take a look – user3852803 Aug 13 '14 at 14:03
  • Your code is essentially attempting to do what my code does, without the clarity of the use of standard, tested functions. You can simply memcpy to/from a buffer if you wish, rather than sending and receiving. – Robert Allan Hennigan Leahy Aug 13 '14 at 14:09
  • My code after serializing the whole structure send it over the network using standard sendto function but just once . It is not logical to have as much sendto calls as much you have members in your structure. You can not just memcpy , you must do serialization and deserialization in order to know what you have in the structure. – user3852803 Aug 13 '14 at 14:15
  • I don't think you're understanding what I'm saying. My answer lays out how the structure can be serialized and sent/received. But there's no reason you have to use `send` and `recv`, you can just `memcpy` to/from a buffer (rather than sending or receiving over the network) and achieve the same result. – Robert Allan Hennigan Leahy Aug 13 '14 at 14:17
0

Because the sizes of the arrays are known at compile time, you can treat it like the structure in the given example.

Think of char buffer[512];, for your purposes, as being the same as char buffer0, buffer1, buffer2, ..., buffer511;.

Also, using sizeof(struct packet) will still work - again, because the array sizes are known at compile time, the compiler can take them into account when computing the total structure size.

Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • Can you help me now I updated my question with the code example, how can I treat pack.id as a array of integers ? – user3852803 Aug 14 '14 at 08:19