You asked "How does recv() work?", so it may be worth briefly studying a simpler function that does essentially the same thing - read().
recv() operates in more or less the same way as the read() function. The main difference is that recv() allows you to pass flags in the last argument - but you are not using these flags anyway.
My suggestion would be - before trying to use recv() to read from a network socket - to practice using read() on a plain text file.
Both functions return the number of bytes read - except in the case of an error, in which case they will return -1. You should always check for this scenario - and handle appropriately.
Both functions can also return less than the number of bytes requested. In the case of recv() - and reading from a socket - this may be because the other end has simply not sent all the required data yet. In the case of a reading from a file - with read() - it may be because you have reached the end of the file.
Anyway ...
You will need to keep track of the current offset within your buffer - and update it on each read. So declare a file-scope variable offset.
static off_t offset; static char buffer[1000];
Then - when your 'loop' is running - increment the offset after each read ...
while (1) {
size_t max_len = sizeof(buffer) - offset;
ssize_t count = recv(sock, buffer+offset, max_len, 0);
if (count == -1) {
switch (errno) {
case EAGAIN:
usleep(20000);
break;
default:
perror("Failed to read from socket");
close(sock);
break;
}
}
if (count == 0) {
puts("Looks like connection has been closed.");
break;
}
offset += count;
if (offset >= expected_len) {
puts("Got the expected amount of data. Wrapping up ...");
}
}
Notes:
- Using this approach, you will either need to know the expected amount of data before-hand - or use a special delimiter to mark the end of the message
- the
max_len variable indicates how much space is left in your buffer - and (perhaps needless to say) you should not try to read more bytes than this
- the destination for the
recv() command is buffer+offset - not buffer.
- if
recv() returns zero, AFAIK this indicates that the other end has performed an "orderly shutdown".
- if
recv() returns -1, you really need to check the return code. EAGAIN is non-fatal - and just means you need to try again.
recvdoes no looping on its own. You need to do that, as well as any bookkeeping necessary to reassemble chunks of data into the final application data. Allrecvdoes and similar is deliver raw data from the socket to the application. The man page can tell you more. - yano