0

I am trying to send a structure over a socket in TCP. However when I receive the data at the structure I am getting an empty structure.

This is the structure being sent by the client:

typedef struct NwInfo
{
    void *pvData;
    NwTypes e_recv;
}NwInfo;

struct NwInfo test;
test.e_recv = 1;
test.pvData = (void *) &pst; //pst is object of another structure.

int ret =send(sockfd,&test,sizeof(test),0); //ret returns greater than 0

At the server side:

 NwInfo *pRecvNwInfo;
 pRecvNwInfo = malloc(sizeof(NwInfo));

 int nbytes = recv(filedes,pRecvNwInfo,sizeof(NwInfo),0);
 //nbytes is the same value as that of ret

 struct student *pst;
 pst = (struct student *)pRecvNwInfo->pvData;

The pst variable in the server side does not get any data. Could anyone point out the error I am making ?

user1692342
  • 5,007
  • 11
  • 69
  • 128
  • possible duplicate of [Write "complex" structures on a FIFO](http://stackoverflow.com/questions/26235345/write-complex-structures-on-a-fifo) - the general issue is independant of whether its a `FIFO` or a `socket` – Andreas Fester Nov 03 '14 at 07:24
  • Another detail: Unless it is a UDP socket you can not just assume one write on the server side equals one read on the client side. Data can be split or merged. Buffering is required. – perh Nov 03 '14 at 08:02

3 Answers3

1

There is no problem with your Socket Programming.
What you need to look at, is the logic.

Here the Server and Client are two different process, having its own address space.

Your Socket programming is perfectly fine. For Example:

Client Side :

send(sockfd, &test, sizeof(test), 0)
printf ("Value of test->e_recv = [%d]\n", test.e_recv);
printf ("Value of test->ptr    = [%u]\n", test.ptr);

$ ./client 172.16.7.110 56000
Value of test->e_recv = [1]
Value of test->ptr    = [3214048236]  // Address of some variable in Client address space.
Data Sent!

Server will recieve exactly the same data.
Server Side:

NwInfo *pRecvNwInfo = malloc(sizeof(NwInfo));
int nbytes = recv(filedes, pRecvNwInfo, sizeof(NwInfo), 0);
printf("Value of pRecvNwInfo->e_recv = [%d]\n", pRecvNwInfo->e_recv);
printf("Value of pRecvNwInfo->ptr    = [%u]\n", pRecvNwInfo->ptr);

$./server 56000
Here is the message.
Value of pRecvNwInfo->e_recv = [1]
Value of pRecvNwInfo->ptr    = [3214048236]   // Address received correctly, but it is of client address space 

So when you write this:

pst = (struct student *)pRecvNwInfo->pvData;

pst is pointing to the address, which is valid only in client address context.
So accessing it (in server's context) will give you Undefined Behavior, In my case SIGSEGV.

Important Note:
When you send, you are sending the data in the address of test and when you recv it, you are receiving the data in some new container (pRecvNwInfo) with a different address.

How to Rectify this:
Its best to send values and not the address. Consider the following structure:

    typedef struct inner
    {
        int a;
        int b;
    }inner_t;


    typedef struct outer
    {
        void *ptr;
        int c;
    }outer_t;        
  1. You may change your Structure definition of outer: Change the void * to actual data and not address, something like. inner_t var.

    send(sockfd, &test, sizeof(test), 0);
    
  2. Create a temporary structure type (for Sending & Receiving).

    /* Temporary Buffer Declaration */
    typedef struct temp{
        inner_t value_in;
        outer_t value_out;
    } temp_t;
    
    temp_t to_send;
    
    inner_t buffer_in;
    /* Save values instead of address */
    memcpy(buffer_in, ptr, sizeof(inner_t));
    
    to_send.value_in = buffer;
    to_send.value_out = outer;
    
    /* Send the final structure */
    send(sockfd, &to_send, sizeof(temp_t), 0);
    

These may not be the best practices, I would love to know if there are any better ones.

Saurabh Meshram
  • 8,106
  • 3
  • 23
  • 32
  • Thanks Got the mistake I was doing. I converted the structure into a character buffer and decoded it at the server – user1692342 Nov 03 '14 at 16:31
0

You need to copy the value of pst in test.pvData member using memcpy. You are just assigning the memory address to test.pvData, value of which wont be available on server side. You can do something like this:

memcpy(test.pvData, &pst, sizeof pst);

Edit: You will also have to give some memory space to pvData instead of just being a pointer.

awatan
  • 1,182
  • 15
  • 33
  • I added test.pvData = malloc(sizeof(pst)); followed by memcpy as mentioned by you. But it did not make any difference – user1692342 Nov 03 '14 at 07:33
  • this is a correct approach. you must have more errors in your code. Show it as an edit in your question. – zoska Nov 03 '14 at 09:36
0

You cant just use sizeof(test) when sending the buffer since sizeof(test) will hold the size of the struct in the memory and since the data you wish to send is only pointed to by the struct it will NOT be included in that size. instead, hold the size of the data you wish to send, and create a stuct that will hold this value in a field and enough space to copy the data to it. then memcpy all the data to the struct and send it as a whole.

Anyhow I suggest you to fill the data directly in a struct you intend to send if you can this will save the memcpy.

antonpuz
  • 3,256
  • 4
  • 25
  • 48
  • is this fine: char *buf = malloc(sizeof(test) + sizeof(pst)); char *tmp = buf; memcpy(buf, pst,sizeof(pst)); tmp = buf +sizeof(pst); memcpy(tmp,test.e_recv,sizeof(test.e_recv)); – user1692342 Nov 03 '14 at 08:01
  • it depends of pst. if its an array that will work, if its a ptr it wont, also you must figure out how to accept the data, so you will know where the data starts and ends, either by adding a size field or by working with the value returned from recv – antonpuz Nov 03 '14 at 08:02