在Linux机器中使用套接字发送和接收文件时出现C ++问题 [英] C++ issue while sending and receiving a file using sockets within a Linux machine

查看:72
本文介绍了在Linux机器中使用套接字发送和接收文件时出现C ++问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Lorem ipsum dolor sit amet,很容易上手。 Duis quam eros,Fringilla etAccumsan vitae,tincidunt scelerisque lacus。 Nulla facilisi。 Duis eget fringilla erat,sed dignissim libero。 Quisque nec velit auctor,内翻,mollis ipsum。 Suspendisse faucibus erat dolor,一个不礼貌的dolor rutrum a。整数sed tempor orci。 Quisque massa lacus,mollis quis efficitur fermentum,viverra eu lorem。 ut bibendum,velit id pharetra rutrum,ipsum quam rhoncus mauris和eleifend nulla mauris quis velit。

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.

使用此代码:

客户端:

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

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

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

谢谢。

推荐答案

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

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

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

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.

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

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.

这篇关于在Linux机器中使用套接字发送和接收文件时出现C ++问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆