在 Linux 机器中使用套接字发送和接收文件时出现 C++ 问题

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

我正在尝试发送文件 file_to_send.txt:

事实是痛苦本身很重要,其次是肥胖精英。 Duis quam eros, fringilla et accumsan vitae, tincidunt 巧克力湖。没有什么是容易的。这是家庭必需品,但却是一种免费资产。谁都不想当作者,不仅如此,他还很软。喉咙痛,妆也痛。是时候去诊所了。每一团湖水,柔软的都变成了酵母,卡通足球。为了喝酒,他想要那个箭袋,和 rhoncus mauris 一样,没有人会想要 eleifend 的 mauris

使用此代码:

客户端:

#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;
}

服务器端:

#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;
}

到 运行 来自终端的代码:

服务器端:

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

客户端:

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

我没有收到所有文件。 有人可以测试此代码并帮助我解决问题吗?

谢谢。

您需要了解 recv() 调用不会一对一映射到 send() 调用。

这可能会从一开始就引起问题:当您在服务器端发送 ascii 格式的文件大小(例如:508)时,在客户端,您可能会一次收到所有字节。但是您也可能会分段接收它(先是 50,然后是 8),在这种情况下,您的客户会认为大小比预期的要小得多,因此会削减数据。

另请注意,您最初发送 BUFSIZ 的完整缓冲区以交出 ascii 格式的大小。但是在接收大小时,您也可能只接收其中的一部分(例如 10 个字节,足以获得正确的大小)。初始发送的剩余字节将随后到达,但将由循环中期望接收有效负载的第一个调用接收。在这种情况下,这些额外的字节(示例中的 BUFSIZ-10)将代替实际文件内容被接收,因此最后发送的字节将在接收文件的末尾被忽略。