0

According to this solution to send out an image through TCP. Since the code is very elegant compared to other ways and both image and file are data, I believe that we can use almost the same code to send out a file.

So if I want to send a file from a client to a server.

On the client side

  1. get file size
  2. send file size // Above steps will always work, so I will only show code after here
  3. read file content into a buffer

    char buf[size];
    read(fs,buf,size);
    
  4. send the buffer

    int bytes = 0;
    for (uint i = 0;i<size;i+=bytes)
    {
        if ((bytes = send(sock,buf+i,size-i,0))<0)
        {
            fprintf(stderr,"Can not send file\n");
            close(fd);
            return false;
        }
        fprintf(stderr,"bytes write = %d\n",bytes);
    }
    

And on the server side

  1. recv file size
  2. recv stuff into a buffer with size from step 1

    char buf[size];
    int bytes=0;
    for (uint i = 0;i<size;i+=bytes)
    {
        if ((bytes = recv(sock,buf+i,size-i,0))<0)
        {
            fprintf(stderr,"Can not receive file\n");
            return false;
        }
        fprintf(stderr,"bytes read = %d\n",bytes);
    }
    
  3. write buffer to a file

    fwrite(buf,sizeof(char),size,fs);
    

This code will compile and run.

When I send out an cpp binary file(24k) from client to server, since both client and server are on the same machine (OS X), this binary file will be received and can be executed.

But if the server forward the file back to the client, and client forward this file back to the server multiple times, this binary file will be corrupted. But the number of bytes sent and number of bytes received are the same, and the file size is still 24k.

I am wondering what is going wrong here.

Is this an OS bug?

Thanks,

Community
  • 1
  • 1
Lin
  • 1,547
  • 2
  • 12
  • 26
  • Your `recv()` code doesn't handle unexpected end of stream correctly. The loop should terminate if `recv()` returns zero or -1. And if you get an error from `send()` or `recv()` it isn't adequate to just print your own message. You should get the actual error in there somewhere, with `perror()` or `strerror()`. – user207421 Apr 11 '16 at 03:49
  • Yes. I should. From the code I have above if `recv()`/`send()` return -1, then the function will terminate. If they return 0, then it should print number bytes recv/send is 0. But no such message has been printed out when the transmitted binary file fails. – Lin Apr 11 '16 at 17:18
  • Are you sure that buf is size big? (Since the example is not complete, and in its current form it looks okey). If you hexdump the corrupt file, what kind of curruption do you see? Do you have valgrind available? That is always a handy to that can detect some types of memory problems. – Stian Skjelstad Apr 15 '16 at 07:07
  • @StianSkjelstad Hi. Thanks for your suggestions. I installed valgrind and tested my code. But it was not a problem related to memory leak. Later I figured out that when I separated the client and sever into different folders, then there was no problem for file transferring. I think that it should an OS problem when client and sever are placed in to same directory. In that case it is just like copying and pasting the binary over and over again. But somehow the OS failed to handle it. – Lin Apr 17 '16 at 20:51

2 Answers2

3

Neither send(), nor recv(), guarantees that the number of bytes requested will actually be sent or received. In that case, the return value will still be positive, but less than the number of bytes that was requested in the system call.

This is extensively documented in the manual page documentation for send() and recv(). Please reread your operating system's documentation for these system call.

It is the application's responsibility to try again, to send or receive the remaining bytes.

This code assumes that the number of bytes that was sent is the number of bytes it requested to be sent. It does appear to handle recv()'s return status properly, but not send()'s. After a fewer number of bytes was sent, this code still assumes that the entire contents were sent or received, and the fwrite() system call will end up writing junk instead of the latter part of the file.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Hi, I have added code to handle the `send()`. But the problem remains. And when it fails, file size (client side) = # of data write = # of data read = file size(server side). Any Ideas? – Lin Apr 11 '16 at 03:05
-1

If both client and server are in the same folder, then in this case it is just like copying and pasting a file.

So when client send out a file, it will

  1. open file
  2. get file name/size + send name/size + send data
  3. close file

On the server side,

  1. get file name/size
  2. open the same file again
  3. get file content
  4. close file

So the problem will occur on step 2 by causing a race condition.

Lin
  • 1,547
  • 2
  • 12
  • 26
  • This is not a race condition, and there is no evidence in your question that you are sending and receiving the same file, or even that client and server are running in the same host. – user207421 Oct 31 '16 at 04:44