Reputation: 71
I'm trying to understand recv() at a high level. So recv takes data in "chunks" but I'm still not getting how it is precisely handled. Example:
char buffer[1000];
int received= recv(sock, buffer, sizeof(buffer), 0)
Does this mean if I'm receiving a massive file, the buffer, if connected through sock might for example reflect it stored 500 bytes in the received variable, then in a loop receive another 300 bytes, and all 800 bytes of data will be stored in buffer by the end of the loop (lost in the received variable unless accounted for), or does buffer need a pointer to keep track of where it last received the data to store it in then next iteration?
Upvotes: 0
Views: 5565
Reputation: 3012
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:
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 thisrecv()
command is buffer+offset
- not buffer
.recv()
returns zero, AFAIK this indicates that the other end has performed an "orderly shutdown".recv()
returns -1, you really need to check the return code. EAGAIN
is non-fatal - and just means you need to try again.Upvotes: 2
Reputation: 123260
recv
has no context. All it knows that it got some address (pointer) to write into and some maximum size - and then it will try this. It will always start writing with the given address. If for example on wish to add data after some previously received data one can simply give the pointer into the location after the previous data instead of the beginning of the buffer. Of course on should adjust the maximum size it is allowed to read to not overflow the buffer.
Upvotes: 1