【问题标题】:C++ issue while sending and receiving a file using sockets within a Linux machine [duplicate]在Linux机器中使用套接字发送和接收文件时的C++问题[重复]
【发布时间】:2016-06-03 05:41:24
【问题描述】:

我正在尝试发送文件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,一种不正当的 dolor rutrum a。整数 sed tempus orci。 Quisque massa lacus、mollis quis efficitur infantum、viverra eu lorem。 Ut bibendum, velit id pharetra rutrum, ipsum quam rhoncus mauris, eleifend nulla mauris quis velit。

使用此代码:

客户端:

#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"

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

谢谢。

【问题讨论】:

  • "有人可以测试这段代码并帮助我解决问题吗?" you 调试代码并解决问题怎么样?如果您已经尝试过调试,请与我们分享您发现的内容以及无法继续进行的原因。
  • 当我将fwrite(buffer, sizeof(char), len, received_file); 中的变量len 更改为等于8192 的BUFSIZ 时,我收到了所有文件和一些随机字符:^@^@^@^@^@^ @^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
  • 不要让我们从头开始调试这是重点。您的代码中显然有一些调试语句。至少显示这些调试的输出并准确告诉我们结果是什么(输出中缺少一个单词?预期输出的一半?没有输出?等等)。
  • @EJP 你能解释一下 C++ 问题如何与使用不同 API 的 java 问题和 java 答案重复吗?好的,它是套接字,好的,它肯定是另一个问题的副本,但至少提供一个足够接近这个问题的 C++ !

标签: c++ linux sockets client-server


【解决方案1】:

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

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

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

【讨论】:

  • 有没有办法在两个调用之间进行一对一的映射? (我正在使用 sendfile() 发送我的文件)。
猜你喜欢
  • 2016-07-28
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 2012-09-23
  • 1970-01-01
相关资源
最近更新 更多