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

时间:2016-02-21 22:08:25

标签: c++ linux sockets client-server

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

Lorem ipsum dolor坐下来,精神上的精神。 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 fermentum,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"

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

感谢。

1 个答案:

答案 0 :(得分:0)

您需要了解recv()来电不会一对一地映射到send()来电。

这可能从一开始就会出现问题:当您在服务器端发送ascii文件大小(例如:508)时,在客户端部分,您可能会立即收到所有字节。但是你也可能会收到它(先50后8),在这种情况下你的客户会认为尺寸远小于预期并削减了数据。

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