bxshi
bxshi

Reputation: 2292

I send a C structure through socket but can not get it right, always miss some bytes

Update: I add a while to get the remain data, problem solved. thanks you guys.

while(res != rcvread->size + 4) {/* do not get full data */
    tmp = recv(connfd, (void *)rcvread + res, rcvread->size + 4 - res, 0);
    if(tmp == -1)
        printf("error:%s\n",(char *)strerror(errno));
    res+=tmp;
}

I want to send a structure mfsio through socket, the return value of write is 37772, but when I got it from the other program, the return value of read is 32768, that's really odd.

The definition of this structure is here

struct mfsio{
    size_t size;
    char buf[];
};

The send code is here

struct mfsio *sndread;
sndread = malloc(sizeof(struct mfsio) + rcvcmd->size);
res = pread(fd, &(sndread->buf), rcvcmd->size, rcvcmd->offset);
sndread->size = res;
res = write(connfd, sndread, sizeof(struct mfsio) + res);

The receive code is here

struct mfsio *rcvread;
rcvread = malloc(sizeof(struct mfsio) + size);
res = 0;    
res = read(connfd, rcvread, sizeof(struct mfsio) + size);

size equals to rcvcmd->size, and the res of pread is 32678, the res of write is 32772. but res of read is 32678.

How can such thing happened? Does I do something wrong here?

If there is no input from write, the read function will just waiting for some data and just hanging there

If I use a loop to avoid such problem, how can I finally get the entire data structure, I mean if I do loop reading, I will get the remain bytes from the socket, but how can I combine these clips I get?

Upvotes: 1

Views: 1316

Answers (4)

Lentes
Lentes

Reputation: 1

The flag MSG_WAITALL on recv() might also be of interest, as it basically does the whole

 while (!allDataReceived) {
   receiveMoreData();
 }

thing for you.

However, the other answers hinting you that you should send a header with "this is how many bytes will follow" are definitely something you should listen to as well.

Upvotes: 0

Francis Upton IV
Francis Upton IV

Reputation: 19443

You need to do your reads and writes in a loop until all of the expected data is read/written. For the read, you have to read until it returns 0, indicating nothing else is available. Or -1 indicating an error.

Your more recent problem is that you are using pointer arithmetic with your struct pointer:

tmp = recv(connfd, rcvread + res, rcvread->size + 4 - res, 0);

In C when you do pointer arithmetic you are not working with bytes, but you are working with the size of the object (rvcread for example). You should define a char * which is the byte location of where you will read into and then update this as you read through the data.

Upvotes: 8

ugoren
ugoren

Reputation: 16441

Francis Upton's answer seems like the right one, you should certainly follow his advice.
But I have another guess, maybe it's the problem.
You don't show how you get the value of size in the receiver. A reasonable way to do it would be to read 4 bytes from the socket into size. So if you did that, you already read 4 bytes, and will get 4 bytes less in the next read.

Upvotes: 0

Juha Autero
Juha Autero

Reputation: 151

read and write operate on byte streams. There is no guaranty that read will read as many bytes as write wrote to it. Either use sendmsg or put record sizes or record separators into the stream.

Upvotes: 0

Related Questions