1

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?

bxshi
  • 2,252
  • 5
  • 31
  • 50
  • You have to adjust the pointer where you read into as part of the loop, add to it the number of bytes you previously read. Make sure you are using a char pointer for this pointer arithmetic though. – Francis Upton IV Dec 27 '11 at 14:14
  • 1
    struct packings are not portable. You need to send a serialized representation of the data. – u0b34a0f6ae Dec 27 '11 at 19:06
  • @kaizer.se So is there any lib on linux can do that? I've done some google search, but not find one. – bxshi Dec 28 '11 at 08:40
  • @bxshi: see http://www.leonerd.org.uk/code/libpack/ or http://stackoverflow.com/questions/371371/serialize-data-structures-in-c – u0b34a0f6ae Jan 09 '12 at 12:55

4 Answers4

8

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.

Francis Upton IV
  • 19,322
  • 3
  • 53
  • 57
  • I want to get this structure. If I use a loop, then I could only get the left bytes, but not the entire structure. Is there a way to solve that? – bxshi Dec 27 '11 at 14:04
  • 1
    I think you would better receive all of data by loop statement just like above Upton's answer. – Kyokook Hwang Dec 27 '11 at 14:07
  • I add these code to get the remain data, but it returns a `Bad address`. 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; }` – bxshi Dec 27 '11 at 15:37
  • If you still having trouble, can you edit your original post to show the code you are now using that does not work? I can't really see what you are doing from the code in a comment, it's too hard to read. – Francis Upton IV Dec 27 '11 at 18:17
  • I expanded my answer to hopefully address your issue. – Francis Upton IV Dec 27 '11 at 20:16
0

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.

Juha Autero
  • 151
  • 3
0

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.

ugoren
  • 16,023
  • 3
  • 35
  • 65
  • I just read the max possible size of bytes from my receiver, and the data equals or less than that size. – bxshi Dec 27 '11 at 14:34
  • @bxshi: That concept will not work. The sender needs to supply the _actual_ size written, otherwise you cannot determine on the reader side how many bytes to read. – Niklas B. Dec 27 '11 at 14:38
0

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.

Niklas Hansson
  • 503
  • 2
  • 16
Lentes
  • 1