-1

I am using fread function to read file, which I am sending via TCP. I found out, that fread doesn't read the whole file, if the file is binary. I tried everything what i found on the internet, but nothing helped. My code is:

#define BUFSIZE 1024
char buf[BUFSIZE];
FILE *file = fopen(soubor,"rb"); //I do a check which i won't write here
size_t bytes_loaded = 0;    
while (!feof(file))
        {
            bytes_loaded = fread(buf,1,BUFSIZE,file);
            if(bytes_loaded != BUFSIZE)
            {
                if(!feof(file))
                {
                    for(int i = 0; i < 100;i++)
                    {
                        fseek(file,-strlen(buf),SEEK_CUR);
                        bytes_loaded = fread(buf,1,BUFSIZE,file);
                        if(bytes_loaded == BUFSIZE)
                        {
                            break;
                        }
                        else if(i == 99)
                        {
                            fprintf(stderr,"C could't read the file\n");
                            fclose(file);
                            close(client_socket);
                            return 1;
                        }
                    }
                }
            }

            bytestx = send(client_socket, buf, BUFSIZE, 0); 
            if (bytestx < 0)
                perror("ERROR in sendto");
            bzero(buf, BUFSIZE);
            bytes_loaded = 0;
        }

Am I doing something wrong? For example that fread check...

Erik
  • 140
  • 1
  • 10
  • There is this, don't know if it's your problem: https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – Galik Mar 11 '18 at 09:41
  • https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong - please read it – Ed Heal Mar 11 '18 at 09:41
  • 3
    Possible duplicate of [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Gilles 'SO- stop being evil' Mar 11 '18 at 09:42
  • 3
    Also, `strlen(buf)` only works for text, not for binary data. – Bo Persson Mar 11 '18 at 09:44
  • What is this supposed to do? Is it just sending the file through the socket and nothing else? – Galik Mar 11 '18 at 09:51
  • @Galik yes it is – Erik Mar 11 '18 at 09:53
  • @RemyLebeau I had it like that, and it loads the same amount of data as version I posted. I am just confused by that "you need to pass that return value to send instead of BUFSIZE" – Erik Mar 11 '18 at 09:55
  • to be exact, now I have that reading part code like this: while (fread(buf,1,BUFSIZE,file) > 0) { bytestx = send(client_socket, buf, BUFSIZE, 0); if (bytestx < 0) perror("ERROR in sendto"); bzero(buf, BUFSIZE); } – Erik Mar 11 '18 at 09:59
  • 1
    You won't always read in exactly `BUFSIZE` bytes so you should not always send `BUFSIZE` bytes. You should send as many bytes as you read, when is the return value from the `fread()` call. – Galik Mar 11 '18 at 10:02
  • @Galik if i don't put there BUFSIZE, I am not able to trasnfer even text files. It causes troubles on the server side, where I have recv(comm_socket, buff, BUFFSIZE,0); BUFSIZE == BUFFSIZE – Erik Mar 11 '18 at 10:10
  • `recv()` can receive less than `BUFSIZE` is you send less. – Galik Mar 11 '18 at 10:11
  • Yes but it does some matrix trick with buf, it somehow overflows and some characters are repeating when I refill buf. I found out that if send and recv have some third paramtr it works, otherwise it doesn't – Erik Mar 11 '18 at 10:24
  • @Erik: it sounds like you are misusing `recv`, but you didn't show that code. In any case, you should send the file size before sending the file data, that way the receiver knows how much data to expect and can stop calling `recv` when it reaches that amount. Then the actual `BUFSIZE` does not matter. There is no 1-to-1 relationship between the number of bytes that `send` transmits and the number of bytes that `recv` receives. They need to be treated independently. – Remy Lebeau Mar 11 '18 at 16:13

2 Answers2

2

Your whole fread() error handling is wrong, get rid of it (using strlen() on a binary buffer is wrong anyway).

In fact, you shouldn't be using feof() to control your loop. Simply call fread() in a loop until it returns < 1 on EOF or error (use feof() and ferror() to differentiate). And when it returns > 0, you need to pass that value to send instead of passing BUFSIZE.

Try something more like this:

#define BUFSIZE 1024

char buf[BUFSIZE], *pbuf;
FILE *file = fopen(soubor, "rb");
...
size_t bytes_loaded;
do
{
    bytes_loaded = fread(buf, 1, BUFSIZE, file);
    if (bytes_loaded < 1)
    {
        if ((!feof(file)) && ferror(file))
            fprintf(stderr, "Couldn't read the file\n");
        break;
    }

    pbuf = buf; 
    do
    {
        bytestx = send(client_socket, pbuf, bytes_loaded, 0);
        if (bytestx < 0)
        {
            perror("ERROR in send");
            break;
        }
        pbuf += bytestx;
        bytes_loaded -= bytestx;
    }
    while (bytes_loaded > 0);
}
while (bytes_loaded == 0);
fclose(file);
... 
Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
  • I tried it and it still doesn' load the whole file. I am trying pdf file and from 300 KB I get 122 KB – Erik Mar 11 '18 at 10:30
  • @Erik then you are doing something else wrong in code you havent shown yet. Please edit your question to show your `recv` code. – Remy Lebeau Mar 11 '18 at 16:17
  • The problem was using strlen, it did really wierd things. Sizeof works better – Erik Mar 12 '18 at 21:49
1

If you are just shifting bytes from the file to the socket then you can just keep looping on the return value from std::fread which tells you how many bytes you read and then send exactly that many bytes to your send() command.

Something like this (untested) code:

if(FILE* fp = std::fopen(soubor, "rb"))
{

    char buf[1024];

    std::size_t bytesrx;
    while((bytesrx = std::fread(0, 1, sizeof(buf), fp)) > 0)
    {
        int bytestx;
        if((bytestx = send(client_socket, buf, bytesrx, 0) < 0))
        {
            // socket error
            std::cout << "socket error: " << std::strerror(errno) << '\n';
            return EXIT_FAILURE;
        }

    }

    if(bytesrx < 0)
    {
        // file error
        std::cout << "file error: " << std::strerror(errno) << '\n';
        return EXIT_FAILURE;
    }

}
else
{
    // error opening file
}
Galik
  • 42,526
  • 3
  • 76
  • 100