C 当我通过套接字发送图片文件时,为什么字节会有差异?

C 当我通过套接字发送图片文件时,为什么字节会有差异?,c,sockets,byte,client-server,C,Sockets,Byte,Client Server,我目前正在构建一个C/C++应用程序,它通过网络套接字发送和接收图片文件。但是,当我通过套接字发送文件时,与源文件相比,目标文件的字节略有不同 为了使此应用程序正常运行,目标客户端文件必须与源服务器文件在字节方面完全相同 客户端代码: int client_app(int argc, char *argv[]) { // create a socket int network_socket; network_socket = socket(AF_INET, SOCK_ST

我目前正在构建一个C/C++应用程序,它通过网络套接字发送和接收图片文件。但是,当我通过套接字发送文件时,与源文件相比,目标文件的字节略有不同

为了使此应用程序正常运行,目标客户端文件必须与源服务器文件在字节方面完全相同

客户端代码:

int client_app(int argc, char *argv[]) {
    // create a socket
    int network_socket;
    network_socket = socket(AF_INET, SOCK_STREAM, 0);

    // specify an address for the socket
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(9002);
    server_address.sin_addr.s_addr = INADDR_ANY;

    // connect returns an integer
    int connection_status = connect(network_socket, (struct sockaddr *) &server_address, sizeof(server_address));

    if (connection_status == -1) {
        printf("Error making connection to remote socket \n\n");
    }

    // read picture byte array
    printf("Reading picture byte array...\n");
    char p_array[BUFSIZ];

    // convert it back into a pic
    printf("Converting byte array to DNG...\n");
    FILE *image = fopen("out_compressed.GPR", "w");
    int nb;
    while ((nb = read(network_socket, p_array, BUFSIZ)) > 0) {
        fwrite(p_array, 1, nb, image);
        bzero(p_array, BUFSIZ);
    }
    fclose(image);

    // and then close the socket
    close(network_socket);
}
服务器代码:

int server_app(int argc, char *argv[]) {
    char *process_argv[100];
    *process_argv = *argv;
    int process_argc = 0;
    for (int i = 1; i < 6; i++) {
        process_argv[i] = argv[i + 1];
        process_argc++;
    }
    process(process_argc, process_argv);

    // create the server socket
    int server_socket;
    server_socket = socket(AF_INET, SOCK_STREAM, 0);

    // define the port number
    int port = 9002;

    // define the server address
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(port);
    server_address.sin_addr.s_addr = INADDR_ANY;

    // bind the socket to our specified IP and port
    bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));

    // listen for connections on the socket
    listen(server_socket, 5);

    // create client socket for the server to send data to
    int client_socket;
    client_socket = accept(server_socket, nullptr, nullptr);

    // get picture size
    char *fpath = process_argv[4];
    FILE *picture;
    picture = fopen(fpath, "r");
    int size;
    fseek(picture, 0, SEEK_END);
    size = ftell(picture);
    fseek(picture, 0, SEEK_SET);

    // send picture size
    write(client_socket, &size, sizeof(size));

    // send picture as byte array
    char send_buffer[BUFSIZ];
    int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);

    while (!feof(picture)) {
        write(client_socket, send_buffer, nb);
        nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
    }

    // then close the sockets
    close(server_socket);
    close(client_socket);

}
当我在客户端收到一个文件时,它看起来大小相同,但我无法对它执行某些压缩操作,这与源文件不同

在我的终端中运行cmp以比较源文件和目标文件时,我得到以下结果:

compressed.GPR out\u compressed.GPR不同:字符1,第1行

如何使这些文件在字节方面完全相同


谢谢

在客户端发送文件大小,然后发送内容。在服务器中,您假定只发送内容,即您将最初发送的大小信息作为内容存储在新文件中


除此之外,您只需假设write将实际写入给定的所有数据,这是不保证的。因此,您需要检查实际写入的字节数。如果您在Windows上,则最好以二进制形式打开文件,即rb而不是r,wb而不是w,因为您在这里处理的是二进制数据。

在客户端,您发送文件大小,然后发送内容。在服务器中,您假定只发送内容,即您将最初发送的大小信息作为内容存储在新文件中

write(client_socket, &size, sizeof(size));
除此之外,您只需假设write将实际写入给定的所有数据,这是不保证的。因此,您需要检查实际写入的字节数。如果你在Windows上,你最好以二进制文件的形式打开文件,即rb而不是r,wb而不是w,因为你在这里处理的是二进制数据

write(client_socket, &size, sizeof(size));
已将图像文件的大小写入套接字,但未检查写入是否成功。始终检查返回代码,以确保您编写了您认为您所做的。。客户机不使用此信息,而是将其合并到文件中。根据客户端当前的编码方式,完成文件后立即关闭套接字,您可以放弃代码计算并发送长度。当套接字关闭时,文件完成。不需要将长度作为辅助对象发送

此外,图像几乎肯定是二进制信息。使用打开文件

FILE *image = fopen("out_compressed.GPR", "w");

将以文本模式打开,并可能执行一些转换,其中最著名的转换是\r\n到\n并破坏文件。分别用wb和rb打开

已将图像文件的大小写入套接字,但未检查写入是否成功。始终检查返回代码,以确保您编写了您认为您所做的。。客户机不使用此信息,而是将其合并到文件中。根据客户端当前的编码方式,完成文件后立即关闭套接字,您可以放弃代码计算并发送长度。当套接字关闭时,文件完成。不需要将长度作为辅助对象发送

此外,图像几乎肯定是二进制信息。使用打开文件

FILE *image = fopen("out_compressed.GPR", "w");


将以文本模式打开,并可能执行一些转换,其中最著名的转换是\r\n到\n并破坏文件。分别用wb和rb打开。

有两个主要错误

首先,服务器在内容之前写入文件大小,但客户端立即开始读取内容,因此文件大小成为客户端内容的一部分。客户机不需要大小,因此只需不在服务器端发送文件大小即可实现

第二个问题是在使用feof时:

当fread读取文件的最后一部分(即小于缓冲区大小的量)时,设置EOF标志。这意味着feof返回true,在将文件的最后一段写入套接字之前退出循环

更好的处理方法是在从文件中读取1个或更多字节时进行循环:

int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);

while (nb > 0) {
    write(client_socket, send_buffer, nb);
    nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
}

除此之外,您不会对调用的任何函数执行错误检查。您应该检查所有套接字和文件相关函数的返回值,如果失败,则使用perror打印错误消息。

有两个主要错误

首先,服务器在内容之前写入文件大小,但客户端立即开始读取内容,因此文件大小成为客户端内容的一部分。客户机不需要大小,因此只需不在服务器端发送文件大小即可实现

第二个问题是在使用feof时:

当fread读取文件的最后一部分(即小于缓冲区大小的量)时,设置EOF标志。这意味着feof返回true,在写入之前退出循环 将文件的最后一段插入套接字

更好的处理方法是在从文件中读取1个或更多字节时进行循环:

int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);

while (nb > 0) {
    write(client_socket, send_buffer, nb);
    nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
}

除此之外,您不会对调用的任何函数执行错误检查。您应该检查所有套接字和文件相关函数的返回值,如果失败,请使用Pror打印错误消息。

您需要以二进制模式打开文件。选择一个、C或C++,并从问题中删除另一个标记。@ RICHARDCRITTEN感谢您的响应!以二进制模式打开文件并不能解决此问题。当在终端中进行比较时,我现在在FielNeM.GPRE上获得EOF。您需要以二进制模式打开文件。选择一个、C或C++,并从问题中删除另一个标记。@ RICHARDCRITTEN感谢您的响应!以二进制模式打开文件并不能解决此问题。在终端中进行比较时,我现在在filename.GPR上获得EOF。感谢您的回复。删除图片大小的段读取并将其写入客户端套接字并不能解决问题,也不能以二进制模式打开文件。请看我上面对Richard的回复。谢谢您的回复。删除图片大小的段读取并将其写入客户端套接字并不能解决问题,也不能以二进制模式打开文件。请看我上面对Richard的回复。嗨,谢谢你的回复。如何检查服务器中写入的字节数?@GnlTsoChicken写入的字节数或失败时的错误代码是写入的返回值。您好,感谢您的回复。如何检查服务器中写入的字节数?@GnlTsoChicken写入的字节数或失败时的错误代码是写入的返回值。感谢您的回复,您的修复成功了!现在可以理解为什么在比较源文件和目标文件时在源文件之前到达EOF。也将添加一些错误处理。再次感谢!感谢您的回复,您的修复成功了!现在可以理解为什么在比较源文件和目标文件时在源文件之前到达EOF。也将添加一些错误处理。再次感谢!