4

I want to program an application to send a file with sockets:

Here my Server:

   void str_server(int sock)
    {
            char buf[1025];
            const char* filename="test.text";
            FILE *file = fopen(filename, "rb");
            err_abort("Test");
            while (!feof(file))
            {
                int rval = fread(buf, 1, sizeof(buf), file);
                send(sock, buf, rval, 0);
            }
    }

and here my client:

void RecvFile(int sock, const char* filename)
{
    int rval;
    char buf[0x1000];
    FILE *file = fopen(filename, "wb");
    while ((rval = recv(sock, buf, sizeof(buf), 0)) > 0)
    {
        fwrite(buf, 1, rval, file);
    }
    close(sock);
}

My problem is that my client create a file....but dont write the content in the file!

JavaNullPointer
  • 1,199
  • 5
  • 21
  • 43
  • As an aside, you dont need to read every byte and send it down the socket. You could read the entire string into a buffer and send(..) it at one go. About your problem, did you close the file before checking it? – UltraInstinct Mar 26 '12 at 17:02

1 Answers1

9

Add some error handling to your code, that should help you track down the problem. Also note that send(), recv(), fread() and fwrite() are not guaranteed to write/read the entire buffer you specify, so you should take that into account as well.

Also, since TCP is a byte stream, the server needs to indicate when the file ends so the client knows when to stop reading. If you don't send the file size before sending the actual file, the only option is to close the socket when the transfer is done.

Try something like this:

int send_all(int sock, const void *buf, int len)
{
    const char *pbuf = (const char *) buf;

    while (len > 0)
    {
        int sent = send(sock, pbuf, len, 0);
        if (sent < 1)
        {
            // if the socket is non-blocking, then check
            // the socket error for WSAEWOULDBLOCK/EAGAIN
            // (depending on platform) and if true then
            // use select() to wait for a small period of
            // time to see if the socket becomes writable
            // again before failing the transfer...

            printf("Can't write to socket");
            return -1;
        }

        pbuf += sent;
        len -= sent;
    }

    return 0;
}

void str_server(int sock) 
{ 
    char buf[0x1000]; 
    const char* filename = "test.text";
    struct stat s;

    if (stat(filename, &s) == -1)
    {
        printf("Can't get file info"); 
        return;
    }

    FILE *file = fopen(filename, "rb"); 
    if (!file)
    {
        printf("Can't open file for reading"); 
        return;
    }

    // if you need to handle files > 2GB,
    // be sure to use a 64bit integer, and
    // a host-to-network function that can
    // handle 64bit integers...
    long size = s.st_size;
    long tmp_size = htonl(size);
    if (send_all(sock, &tmp_size, sizeof(tmp_size)) == 0)
    {
        while (size > 0)
        { 
            int rval = fread(buf, 1, min(sizeof(buf), size), file); 
            if (rval < 1)
            {
                printf("Can't read from file");
                break;
            }

            if (send_all(sock, buf, rval) == -1)
                break;

            size -= rval;
        }
    }

    fclose(file);
} 

int write_all(FILE *file, const void *buf, int len)
{
    const char *pbuf = (const char *) buf;

    while (len > 0)
    {
        int written = fwrite(pbuf, 1, len, file);
        if (written < 1)
        {
            printf("Can't write to file");
            return -1;
        }

        pbuf += written;
        len -= written;
    }

    return 0;
}

int read_all(int sock, void *buf, int len)
{
    char *pbuf = (char *) buf;
    int total = 0;

    while (len > 0)
    {
        int rval = recv(sock, pbuf, len, 0);
        if (rval < 0)
        {
            // if the socket is non-blocking, then check
            // the socket error for WSAEWOULDBLOCK/EAGAIN
            // (depending on platform) and if true then
            // use select() to wait for a small period of
            // time to see if the socket becomes readable
            // again before failing the transfer...

            printf("Can't read from socket");
            return -1;
        }

        if (rval == 0)
        {
            printf("Socket disconnected")
            return 0;
        } 

        pbuf += rval;
        len -= rval;
        total += rval;
    }

    return total;
}

void RecvFile(int sock, const char* filename) 
{ 
    int rval; 
    char buf[0x1000];

    FILE *file = fopen(filename, "wb"); 
    if (!file)
    {
        printf("Can't open file for writing");
        return;
    }

    // if you need to handle files > 2GB,
    // be sure to use a 64bit integer, and
    // a network-to-host function that can
    // handle 64bit integers...
    long size = 0;
    if (read_all(sock, &size, sizeof(size)) == 1)
    {
        size = ntohl(size);
        while (size > 0)
        {
            rval = read_all(sock, buf, min(sizeof(buf), size));
            if (rval < 1)
                break;

            if (write_all(file, buf, rval) == -1)
                break;
        } 
    }

    fclose(file); 
} 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • missing some statements at the end. The doWhileouter loop – Saad Oct 27 '17 at 02:17
  • so you just removed the outer loop? and changed the condition as well – Saad Oct 27 '17 at 03:41
  • why you removed offset? Seems will not work for larger files having len greater than buffer – Saad Oct 27 '17 at 03:45
  • @Saad The code still works for large files. The outer loops still exist to read files using fixed buffers. I just refactored the code to extract the inner loops to their own functions when writing each buffer to the target, and then the offset logic wasn't needed anymore. – Remy Lebeau Oct 27 '17 at 04:03
  • still it doesn't skips the loop even after reading last bufer and keeps waiting to receive from socket. – Saad Oct 27 '17 at 10:29
  • Fixed it by making the buffer length same to the sender side and making if (rval == 0 || rval < sizeof(buf)) break; worked – Saad Oct 27 '17 at 12:04
  • @Saad TCP is a byte stream. `recv()` returns 0 when the socket is disconnected gracefully. It is allowed to return < sizeof(buf) without losing data. That is not an indication of eof. Since the original code wasn't sending the file size to the client, disconnect is the only way to indicate eof. – Remy Lebeau Oct 27 '17 at 14:08
  • Yes but at receiving side there needed to be some flag that sender will no more send. As it goes to wait state and sender stoped sending. – Saad Oct 27 '17 at 14:20
  • @Saad yes, and since the code is not sending the file in any kind of framing, thus allowing an eof frame, the only possible flag is to send the file size before sending the file data. I have added that now – Remy Lebeau Oct 27 '17 at 14:51
  • Sending is okay. The problem was with receive or may in my case where I m not closing the socket. Anyways thanks – Saad Oct 27 '17 at 15:31