0
votes

I'm building a P2P file sharing program and I can transfer files between computes connected to my Wifi Router. However, when I run it on my computer with localhost address, the sender part of my program successfully sends all the data to the receiver program but my receiver does not get all the data. I'm running these two on seperate ports on my machine. The problem does not occur when I run sender and receiver on seperate machines.

Here's my receive code snippet

    while ((len = recv(welcomeSocket, buffer, BUFSIZ, 0)) > 0 && remain_data > 0)
    {
            fwrite(buffer, sizeof(char), len, received_file);
            remain_data -= len;
            fprintf(stdout, "Receive %zd bytes and we hope :- %d bytes\n", len, remain_data);

    }

And here's my send code snippet

     while (((sent_bytes = sendfile(fds[i].fd, fd, offset, BUFSIZ)) > 0) && (remain_data > 0))
    {
            fprintf(stdout, "Server sent %u bytes from file's data, offset is now : %jd \n", sent_bytes, (intmax_t)offset);
            remain_data -= sent_bytes;
            fprintf(stdout, "remaining data = %d\n", remain_data);
    }

The output at the sender part is

Server sent 8192 bytes from file's data, offset is now : 0 
remaining data = 30292
Server sent 8192 bytes from file's data, offset is now : 0 
remaining data = 22100
Server sent 8192 bytes from file's data, offset is now : 0 
remaining data = 13908
Server sent 8192 bytes from file's data, offset is now : 0 
remaining data = 5716
Server sent 5716 bytes from file's data, offset is now : 0 
remaining data = 0

And the output at the receiver is

Receive 256 bytes and we hope :- 38228 bytes
Receive 8192 bytes and we hope :- 30036 bytes
Receive 8192 bytes and we hope :- 21844 bytes
Receive 8192 bytes and we hope :- 13652 bytes
Receive 5716 bytes and we hope :- 7936 bytes

Once again, this does not happen when running these programs on different machines and recv() gets all the data. Is the communication path at localhost so fast that the recv() is not able to handle the data and hence misses some of it?

Thank you

1
A guess: try closing the fd after the sendfile is complete. Do you keep the socket open in the sender until the receiver is done? It could be that the sender is terminating the socket too quickly. - cdarke
Won't be the cause, but shouldn't you be bumping offset in the sender by the number of bytes sent? - TripeHound
@cdarke, I've tried both the methods, closing or not closing the socket after send. If I close it, the recv() terminates prematurely after the shown messages, If I leave the socket open in the sender, the recv() keeps on blocking expecting more data - Gaurav Suman
@TripeHound, yeah I corrected that, thanks for that cosmetic catch :) - Gaurav Suman
@tripeHound: sendfile() is supposed to increment the offset upon exit. See the documentation: "If offset is not NULL, then it points to a variable holding the file offset from which sendfile() will start reading data from in_fd. When sendfile() returns, this variable will be set to the offset of the byte following the last byte that was read. If offset is not NULL, then sendfile() does not modify the current file offset of in_fd; otherwise the current file offset is adjusted to reflect the number of bytes read from in_fd." - Remy Lebeau

1 Answers

1
votes

Assuming that remain_data is the actual file size, then both of your loops are wrong. They should be more like this:

while (remain_data > 0)
{
    len = recv(welcomeSocket, buffer, min(remain_data, BUFSIZ), 0);
    if (len <= 0) {
        // error handling...
        break;
    }
    fwrite(buffer, sizeof(char), len, received_file);
    remain_data -= len;
    fprintf(stdout, "Receive %zd bytes and we hope :- %d bytes\n", len, remain_data);
}

off_t offset = 0;
while (remain_data > 0)
{
    sent_bytes = sendfile(fds[i].fd, fd, &offset, min(remain_data, BUFSIZ));
    if (sent_bytes <= 0) {
        // error handling...
        break;
    }
    fprintf(stdout, "Server sent %u bytes from file's data, offset is now : %jd \n", sent_bytes, (intmax_t)offset);
    remain_data -= sent_bytes;
    fprintf(stdout, "remaining data = %d\n", remain_data);
}