0

I'm using C to implement a client server application. The client sends info to the server and the server uses it to send information back. I'm currently in the process of writing the code to handle the receiving of data to ensure all of it is, in fact, received.

The issue I'm having is best explained after showing some code:

int totalRead = 0;
char *pos = pBuffer;
while(totalRead < 6){
if(int byteCount = read(hSocket, pos, BUFFER_SIZE - (pos-pBuffer)>0)){
    printf("Read %d bytes from client\n", byteCount);
    pos += byteCount;
    totalRead += byteCount;
    }else return -1;
}

The code above runs on the server side and will print out "Read 1 bytes from client" 6 times and the program will continue working fine. I've hard-coded 6 here knowing I'm writing 6 bytes from the client side but I'll make my protocol require the first byte sent to be the length of rest of the buffer.

int byteCount = read(hSocket, pBuffer, BUFFER_SIZE);
printf("Read %d bytes from client", byteCount);

The code above, used in place of the first code segment, will print "Read 6 bytes from client" and continue working fine but it doesn't guarantee I've received every byte if only 5 were read for instance.

Can anyone explain to me why this is happening and a possible solution? I guess the first method ensures all bytes are being delivered but it seems inefficient reading one byte at a time...

Oh and this is taking place in a forked child process and I'm using tcp/ip.

Note: My goal is to implement the first code segment successfully so I can ensure I'm reading all bytes, I'm having trouble implementing it correctly.

pandaEater
  • 165
  • 2
  • 5
  • 11
  • Your protocol should also include some length or content delimiters to let the other party know when it should stop receiving data (similar to `Content-Length` or chunked encoding in HTTP). See http://stackoverflow.com/a/6404085/372643 – Bruno Jan 17 '12 at 15:08

2 Answers2

6

Basically the right way to do this is a hybrid of your two code snippets. Do the first one, but don't just read one byte at a time; ask for all the bytes you're expecting. But look at bytesRead, and if it's less than you expected, adjust your destination pointer, adjust your expected number read, and call read() again. This is just how it works: sometimes the data you're expecting is split across packets and isn't all available at the same time.

Reading your comment below and looking at your code, I was puzzled, because yeah, that is what you're trying to do. But then I looked very closely at your code:

read(hSocket, pos, BUFFER_SIZE - (pos-pBuffer)>0)){
                                              ^
                                              |
                                THIS ---------|

That "> 0" is inside the parentheses enclosing read's arguments, not outside; that means it's part of the arguments! In fact, your last argument is interpreted as

(BUFFER_SIZE - (pos-pBuffer)) > 0

which is 1, until the end, when it becomes 0.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • Yes! that's what I've been trying to do but the problem is I can't figure out how NOT to ask for only byte at a time. I was assuming first code segment above was asking for all the bytes. In the first case above if I use read(socket, pos, BUFFER_SIZE - (pos-pBuffer)) wouldnt it be trying to read the whole thing since (pos-pBuffer) = 0 on the first try, thus my third arg would be the whole buffer size? – pandaEater Jan 17 '12 at 04:00
  • See my edit. Please don't hurt your forehead banging it against your desk. – Ernest Friedman-Hill Jan 17 '12 at 04:08
  • Ahhhh that hurts... so much wasted time. But thanks a lot for your help! – pandaEater Jan 17 '12 at 04:11
  • @pandaEater, please upvote (click the up arrow) each answer that helped you. Please accept (click the check mark) the best answer. – Robᵩ Jan 17 '12 at 19:28
0

Your code isn't quite right. read and write may not read or write the total amount of data you've requested they should. Instead, you should advance the read or write pointer after each call and count how many bytes you have left to submit with in the transmission.

If you get back negative one from either read or write you've gotten an error. A zero indicates the transmission completed (there were no more bytes to send) and any number above zero indicates how many bytes were sent in the last call to read or write respectively.

jmkeyes
  • 3,751
  • 17
  • 20
  • Can you show me some an example of code that is right? My first code segment is trying to do what you're explaining but I'm having trouble getting it to work properly. – pandaEater Jan 17 '12 at 04:09