C++ issue while sending and receiving a file using sockets within a Linux machine [duplicate]

别说谁变了你拦得住时间么 提交于 2019-12-12 04:05:53

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/35542760/c-issue-while-sending-and-receiving-a-file-using-sockets-within-a-linux-machin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!