views:

835

answers:

1

I'm trying to receive some file through sockets in C. But the server sends me 64-byte packets for a 1000000 byte file for example and I get approximately 999902 bytes on the destination file.

while ((n = read(sd, buffer_in, BUFSIZE ))) //  BUFSIZE = 64 
{
    if(n<0)
    {
       printf("Fail.\n");
       fclose(archivo);
       return -1;
    }

    if(fwrite(buffer_in, n, 1, f) !=1 ) 
    { 
       printf("fwrite error.\n");
       fclose(archivo);
       return -1;
    }

    bytes+=n;
}

printf("We received %d bytes",  bytes);

When used through a local TCP/IP socket it works, but not in a slow connection. I see through debugging that I get a lot of 64 byte chunks, and a 30 byte chunk near EOF. I know that you can get less bytes on read() since the call returns when any data (>1 byte) is available. But this condition shouldn't be catched by the while? Should return when n == 0, that is no more data (EOF).

Thx for your help.

(EDIT)

Sending code as follows:

while (n=read(file_fd, buffer, BUFSIZE))
{
   write (sdaccept, buffer, n)
}

I know that both read() and write () may return N < BUFSIZE, but shouldn't this loop work out that accordingly? I added up n and returns 1000000, the exact size.

(EDIT II)

Tested with a C source with 10673 bytes, receives 10575 without corruption, except that the destination file LACKS the first 98 bytes!!!

+12  A: 

The sending code provided ignores the fact that write() (or send() ) on a socket is not obliged to write the whole buffer.

write()/send() might decide to write it partially or not write at all if the underlying subsystem refuses to receive more data (for example the network subsystem may have a queue for the data to send and this queue is already full). That's highly likely on a slow connection.

The sending side should check the return value of write() to detect how much data has been actually written and adjust accordingly.

Write should be done somehow like this:

int readAmount;
while( readAmount = read(file_fd, buffer, BUFSIZE) > 0 )
{
    int totalWritten = 0;
    do {
       int actualWritten;
       actualWritten = write (sdaccept, buffer + totalWritten, readAmount - totalWritten);
       if( actualWritten == - 1 ) {
           //some error occured - quit;
       }
       totalWritten += actualWritten;
    } while( totalWritten < readAmount );
}
sharptooth
Sending side code added.
Hernán
Sending code is prone exactly to the problem I described. Suggested fix added.
sharptooth
Still transfers 999902 bytes!!!! :( :(
Hernán
More specifically, there are 1M bytes write but less received ! :(
Hernán
You mean, you sum the totalWritten for all the iterations and it's 1M but the receiving party still receives incomplete data?
sharptooth
yes, final file size on disk is < 1M! (999902)
Hernán
The last received data size is 30 bytes , seems that after that receipt reads gets EOF
Hernán
You should try to detect what data is missing exactly. For example, after you've read a block from disk, write an integer into its first four bytes and increment that integer. Inspect it on the receiving side.
sharptooth
Used cmp -b file1 file2 both seems to be equal!!! I will try to modify the input like you say.
Hernán
They can't be equal if they are of different size. Perhaps they are equal from beginning to the end of the shortest file. This means that the end of file gets lost.
sharptooth
tested now with C source (10673 bytes), receives 10575. Lacks the FIRST 98 bytes, not the last!!
Hernán
That's strange. Doesn't any of read/write functions ever return -1 in the process?
sharptooth
Look this is not my code, i'm fixing a total mess. how about sending through the same socket previous to the read in the receiver? This program sends the file name to the server before the while loop. Maybe there are some chars left there? I need to flush that socket.. :)
Hernán
How do you send the filename? Just the buffer without specifying the name length?
sharptooth
This program was coded horribly. In the depths of nested function calls, I found a recv lying there!!! MY GOD! I'm on the right path now. The programmer must be shot.
Hernán
FIXED. Impromper read/write pairing on server/client code.
Hernán