#1
  1. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2003
    Posts
    24
    Rep Power
    0

    Passing a dynamic array across a network


    Hello!

    I have a structure defined as follows:
    struct info {
    int num;
    char* d;
    };

    This structure is defined on both the client and the server sides of the program identically. When the client starts, I know how many bytes the char* will need to be. So on the client side I say:

    struct info i;
    i.d = (char*)(malloc(sizeof(char) * size));
    strncpy(i.d, "Hello World", size);
    sendto(sock, &i, sizeof(i), 0, (struct sockaddr *)&server, sizeof(server));

    Please assume that size is bigger than the length of "hello world" for this example. Also assume that the socket information is set up correctly.

    I am using a UDP socket interface so I am using the sendto function on the client side.

    On the server side, to receive this struct I have:

    struct info i;
    i.d = (char *)(malloc(sizeof(char) * size));
    length = sizeof(sock);
    recvfrom(s, &i, sizeof(i), 0, (struct sockaddr *)&sock, &length);

    However, I do not receive the proper data. Is there a way to pass across a char* that holds a variable amount of data? Is so, how do you do so? Thanks for you help
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,171
    Rep Power
    2222
    OK, I'm game for a bit of brain-storming. If nothing else, I'll see if the coffee has kicked in yet.

    The main problem I see here is that i.d on the client side points to data that resides elsewhere in the client's memory. If all we send to the server is that pointer, then on the server i.d will be pointing to whatever already resides in the server's memory at that location, AKA "garbage" -- even though one process' data is another process' garbage, to the server it'll be garbage.

    The way I see it, we must include the data in the packet, since it is the data that the server needs, not its location in the client. Off the top of my head, I see a couple different ways of doing this.

    My first thought was to embed the data in the structure, effectively replacing the pointer with the data it was pointing to, then the server would translate that back to the original structure. Of course, it didn't take me long to reject this idea. It's too complicated and requires too much translating back and forth. I only mention it in case it sparks an idea for you.

    My second thought was better, I think. The structure resides in the beginning of the packet, as it already does now. Then add the character string after that, complete with null terminator. Finally, change the pointer i.d to the offset of the string from the beginning of the packet. That way, a struct with multiple char* fields can be accommodated easily; multiple strings would follow the packet, each one properly pointed to by its corresponding char* in the struct. Also, you can set the packet size dynamically to accommodate any size and number of strings -- assuming that you don't exceed the max size allowed for UDP packets (255 bytes, if I remember right).

    On the server side, the struct would be copied over directly from the packet to a struct in the server's memory. Then for each char* field, use the offset to find the string in the packet, strlen() it to get its length, malloc it locally, and strcpy it into that malloc'd memory.

    More complex linked data structures would be more of a challenge, but this approach might even work for them. Though the packet size would probably become too great, requiring you to go to TCP.

    Does that look like it would work? I haven't gotten to that point yet in my network programming (have just done a basic embedded telnet client and some time clients and servers), but I should eventually get to the point where I'll need to do the same thing.

    If you need to research it further, some of the techniques for saving pointer-data linkage to a disk file might also be applicable to this problem.
    Last edited by dwise1_aol; April 12th, 2003 at 11:27 AM.
  4. #3
  5. *bounce*
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2002
    Location
    Delft, The Netherlands
    Posts
    514
    Rep Power
    42
    Here's what I slapped together to give you an idea:

    Code:
    struct info {
            int num;
            char* d;
    };
    
    
    void send_struct (struct info *i)
    {
            void *packet;
            int len;
    
            len = strlen(i->d);
    
            packet = malloc(sizeof(*i) + len + 1);
            /* error handling omitted */
    
            memcpy(packet, i, sizeof(i));
            memcpy(packet + sizeof(i), i->d, len + 1);
    
            /* ...code that sends the packet... */
    }
    
    void receive_struct (struct info *i)
    {
            void *packet;
    
            /* ...code that receives the packet... */
    
            memcpy(i, packet, sizeof(i));
            i->d = strdup(packet + sizeof(i));
            /* again, error handling omitted */
    }
    If struct info will never be more than an integer and a string, you might consider not sending the struct at all, but just allocate some memory to store the integer and the string data.

    For more complex structs, dwise1's idea (which I sort of implemented, except for the pointer offsets) would be more appropriate.

    Good luck :)
    "A poor programmer is he who blames his tools."
    http://analyser.oli.tudelft.nl/
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,171
    Rep Power
    2222

    Re: Passing a dynamic array across a network


    Originally posted by campbel8
    Hello!

    I have a structure defined as follows:
    struct info {
    int num;
    char* d;
    };
    Following up on another thread in the Linux section, I rediscovered that you need to convert the byte-order of integers in a packet's data. Every integer value going out needs to be passed through htons() or htonl() and every one being received needs to be passed through ntohs() or ntohl(). You're already doing it for the port number in the address struct; you just need to do the same for your data.

    You can get away with not converting the byte order of your data only as long as you restrict yourself to architectures that use the same host byte order (eg, intel boxes running Windows and/or Linux). But as soon as a machine with a different host byte order tries to run either your client or your server, then the data will be misinterpreted and hence corrupted. I just tested this out on an NTP client I had written.

    I'm not sure about floating-point numbers, but I'm pretty sure that they're also subject to host byte order.
    Last edited by dwise1_aol; April 14th, 2003 at 02:04 PM.

IMN logo majestic logo threadwatch logo seochat tools logo