0

I am trying to send the file file_to_send.txt:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quam eros, fringilla et accumsan vitae, tincidunt scelerisque lacus. Nulla facilisi. Duis eget fringilla erat, sed dignissim libero. Quisque nec velit auctor, varius ex id, mollis ipsum. Suspendisse faucibus erat dolor, a imperdiet dolor rutrum a. Integer sed tempus orci. Quisque massa lacus, mollis quis efficitur fermentum, viverra eu lorem. Ut bibendum, velit id pharetra rutrum, ipsum quam rhoncus mauris, a eleifend nulla mauris quis velit.

using this code:

Client side:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>

#define PORT  16000
#define ADDRESS  "localhost"


int main(int argc, char **argv)
{
        int client_socket;
        ssize_t len;
        struct sockaddr_in remote_addr;
        char buffer[BUFSIZ];
        int file_size;
        FILE *received_file;
        int remain_data = 0;
    char* destination_path = argv[1];


        memset(&remote_addr, 0, sizeof(remote_addr));


        remote_addr.sin_family = AF_INET;
        inet_pton(AF_INET, ADDRESS, &(remote_addr.sin_addr));
        remote_addr.sin_port = htons(PORT);


        client_socket = socket(AF_INET, SOCK_STREAM, 0);
        if (client_socket == -1)
        {
                fprintf(stderr, "Error creating socket --> %s\n", strerror(errno));

                exit(EXIT_FAILURE);
        }


        if (connect(client_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
        {
                fprintf(stderr, "Error on connect --> %s\n", strerror(errno));

                exit(EXIT_FAILURE);
        }


        recv(client_socket, buffer, BUFSIZ, 0);
        file_size = atoi(buffer);
        fprintf(stdout, "\nFile size : %d\n", file_size);

        received_file = fopen(destination_path, "w");
        if (received_file == NULL)
        {
                fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));

                exit(EXIT_FAILURE);
        }

        remain_data = file_size;
    while ((len = recv(client_socket, buffer, BUFSIZ, 0) > 0) && (remain_data > 0))
        {
        fwrite(buffer, sizeof(char), len, received_file);
        remain_data -= len;
                fprintf(stdout, "Receive %d bytes and we hope :- %d bytes\n", static_cast<int>(len), remain_data);
        }
        fclose(received_file);

        close(client_socket);

        return 0;
}

Server side:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
using namespace std;
#define PORT     16000
#define ADDRESS  "localhost"


int main(int argc, char **argv)
{
        int server_socket;
        int peer_socket;
        socklen_t       sock_len;
        ssize_t len;
        struct sockaddr_in      server_addr;
        struct sockaddr_in      peer_addr;
        int fd;
        int sent_bytes = 0;
        char file_size[BUFSIZ];
        struct stat file_stat;
        off_t offset;
        int remain_data;

    char* file_to_serve = argv[1];


        server_socket = socket(AF_INET, SOCK_STREAM, 0);
        if (server_socket == -1)
        {
                fprintf(stderr, "Error creating socket --> %s", strerror(errno));

                exit(EXIT_FAILURE);
        }


        memset(&server_addr, 0, sizeof(server_addr));

        server_addr.sin_family = AF_INET;
        inet_pton(AF_INET, ADDRESS, &(server_addr.sin_addr));
        server_addr.sin_port = htons(PORT);


        if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1)
        {
                fprintf(stderr, "Error on bind --> %s", strerror(errno));

                exit(EXIT_FAILURE);
        }


        if ((listen(server_socket, 5)) == -1)
        {
                fprintf(stderr, "Error on listen --> %s", strerror(errno));

                exit(EXIT_FAILURE);
        }

        fd = open(file_to_serve, O_RDONLY);
        if (fd == -1)
        {
                fprintf(stderr, "Error opening file --> %s", strerror(errno));

                exit(EXIT_FAILURE);
        }


        if (fstat(fd, &file_stat) < 0)
        {
                fprintf(stderr, "Error fstat --> %s", strerror(errno));

                exit(EXIT_FAILURE);
        }

        fprintf(stdout, "File Size: \n%d bytes\n",static_cast<int>(file_stat.st_size));

        sock_len = sizeof(struct sockaddr_in);

        peer_socket = accept(server_socket, (struct sockaddr *)&peer_addr, &sock_len);
        if (peer_socket == -1)
        {
                fprintf(stderr, "Error on accept --> %s", strerror(errno));

                exit(EXIT_FAILURE);
        }
        fprintf(stdout, "Accept peer --> %s\n", inet_ntoa(peer_addr.sin_addr));

        sprintf(file_size, "%d", static_cast<int>(file_stat.st_size));


        len = send(peer_socket, file_size, sizeof(file_size), 0);
        if (len < 0)
        {
              fprintf(stderr, "Error on sending greetings --> %s", strerror(errno));

              exit(EXIT_FAILURE);
        }

        fprintf(stdout, "Server sent %d bytes for the size\n", static_cast<int>(len));

        offset = 0;
        remain_data = file_stat.st_size;

    while (((sent_bytes = sendfile(peer_socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0))
        {
        fprintf(stdout, "Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes,          static_cast<int>(offset), static_cast<int>(remain_data));
                remain_data -= sent_bytes;
                fprintf(stdout, "Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes,          static_cast<int>(offset), static_cast<int>(remain_data));
        }

        close(peer_socket);
        close(server_socket);

        return 0;
}

To run the code from terminal:

Server side:

// compile
$ g++ server.cpp -o server_side
// run client
$ ./server_side "$HOME/file_to_send.txt"

Client side:

// compile
$ g++ client.cpp -o client_side
// run client
$ ./client_side "$HOME/received_file.txt"

I don't receive all the file. Can someone test this code and help me fix the issue?

Thanks.

Omar
  • 139
  • 1
  • 7
  • "Can someone test this code and help me fix the issue?" How about *you* debug the code and fix the problem? If you have already tried to debug then share with us what you found and why you could not proceed. – kaylum Feb 21 '16 at 22:16
  • when I change the variable `len` in the `fwrite(buffer, sizeof(char), len, received_file);` to BUFSIZ which is equal to 8192, I receive all the file and some random characters: ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^ – Omar Feb 21 '16 at 22:26
  • Don't make us debug this from scratch is the point. You obviously have some debug statements in your code. At a minimum show the output of those debugs and tell us exactly what the result is (one missing word in the output? half the expected output? no output? etc). – kaylum Feb 21 '16 at 22:33
  • @EJP can you explain how a C++ question can be a duplicate of a java question and java answers which use a different API ? Ok it's sockets, and ok, It's certainly a duplicate of another question, but at least provide a C++ one close enough to this question ! – Christophe Feb 22 '16 at 22:55

1 Answers1

0

You need to understand that the recv() calls will not map one to one to the send() calls.

This may cause problems from the beginning: when you send on the server side the file size in ascii (example: 508), on the client part, you may receive all the bytes at once. But you also may receive it in pieces (first 50 then 8) in which case your client will think that the size is much smaller than expected and cut the data.

Note also that you initially send a full buffer of BUFSIZ to hand over the size in ascii. But on receiving size, you might also receive only a part of it (say 10 bytes for example, so enough to get the right size). The remaining bytes of the initial sending will then arrive, but will be received by the first of the call in the loop that expect to receive the payload. In this case, these extra bytes (BUFSIZ-10 in the example) will be received in place of real file content, so taht the last bytes sent would be ignored at the end of the received file.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Is there a way to do a one to one mapping between the two calls? (I am using sendfile() to send my file). – Omar Feb 22 '16 at 15:30