Linux服务器,向Windows客户端发送文件(Socket)

4

当我将文件发送给客户端时,它会变得损坏,并且大小以字节为单位更大。

我在Windows上运行了此服务器的版本,完美地工作,但是在Linux上没有同样的结果。

磁盘上的文件大小可能是发送字节大小到在另一个平台上运行的客户端时出错的原因吗?

客户端方面完美地工作,正如我所说,我有一个在Windows上运行的此服务器的版本,唯一的区别在于fread:Size = fread(mfcc, 1, min(sizeof(mfcc), FileSize), fp);

fread函数被正确使用吗?

专家可以分析并帮助找到错误吗?

int Socket_Setup::FILE_UPLOAD(int iD, std::string DIR_UPLOAD)
{   
    char Block[1024]; 
    long FileSize;      
    fp = fopen(DIR_UPLOAD.c_str(), "rb");
    if (!fp)
    {
          errno_message.append((char*)strerror(errno));
          FUNCTION_LOG(errno_message);
          return 1;
    }

    fseek(fp, 0, SEEK_END);
    FileSize = ftell(fp);
    rewind(fp);

    long Size_Send = htonl(FileSize);
    Total = FileSize;

    // Sending the file size to the Windows Client  
    iResult = send(client[iD].socket, (const char*)&Size_Send, sizeof(long), 0);        
    if (iResult <= 0)
    {
          errno_message.append((char*)strerror(errno));
          FUNCTION_LOG(errno_message);
          return 1;
    }   

     while (FileSize > 0)
    {
        BytesRead = fread(Block, 1, sizeof(Block), fp);
        if (BytesRead <= 0)
        {
            errno_message.append((char*)strerror(errno));
            FUNCTION_LOG(errno_message);
            fclose(fp);
            return 1;
        }
        if (send(client[iD].socket, Block, BytesRead, 0) != BytesRead)
        {
            errno_message.append((char*)strerror(errno));
            FUNCTION_LOG(errno_message);
            fclose(fp);
            return 1;
        }
        FileSize -= BytesRead;      
    }
    fclose(fp);
    return 0;
}
2个回答

3
我认为你的问题在这里:

我想你的问题就出在这里:

iResult = send(client[iD].socket, (const char*)&Size_Send, Size_Send, 0);       

你正在发送Size_Send字节,包括Size_Send变量后面的杂项内存(大多数是不相关的),而你真正想发送的是sizeof(long)字节。请将上述行中的第二个Size_Sent替换为sizeof(long),这样可以得到更好的结果。

现在字节大小几乎相等,但仍然会出现损坏的文件。 - Melissia_M
没错,我对 fread 函数不是很了解,我该怎么办? - Melissia_M
腐败的性质是什么? - keithmo
文件无法打开,我尝试发送了一个jpg文件,但是文件无法显示,同时也从服务器接收到了文件的大部分字节。 - Melissia_M
你尝试过运行WireShark来查看实际传输的字节吗?如果通过传输的字节与文件中的字节匹配,那就表明错误出现在接收端而不是发送程序中。 - Jeremy Friesner

2
假设使用POSIX套接字(IEEE Std 1003.1, 2013版)

分析

让我们考虑以下代码片段:

  1. Sending the file size.

    // Sending the file size to the Windows Client  
    iResult = send(client[iD].socket, (const char*)&Size_Send, sizeof(long), 0);
    if (iResult <= 0)
    {
          errno_message.append((char*)strerror(errno));
          FUNCTION_LOG(errno_message);
          return 1;
    }
    
  2. Sending the "block".

    if (send(client[iD].socket, Block, BytesRead, 0) != BytesRead)
    {
        errno_message.append((char*)strerror(errno));
        FUNCTION_LOG(errno_message);
        fclose(fp);
        return 1;
    }
    
send()函数不能保证所有数据一次性发送(即使用单个函数调用):

返回值

成功完成后,send()函数应返回已发送的字节数。否则将返回-1并设置errno以指示错误。

send - 在套接字上发送消息,The Open Group Base规范第7版,IEEE Std 1003.1,2013年版.

因此,if (send(client[iD].socket, Block, BytesRead, 0) != BytesRead)检查似乎不正确。

解决方案

必须使用send()函数的返回值来实现循环发送之前由fread()函数调用读取的所有字节。 请参见SendAllBytes()函数的实现。它应该用于更正两个代码片段(请参见“分析”部分)。
以下代码仅应视为示例:
#include <stdio.h>
#include <sys/socket.h>

...

if (SendAllBytes(socket, &file_size, sizeof(file_size)) != 0) {
    // Error.
    return;
}

...

char buffer[1024];
while (feof(file_stream) == 0) {
    const size_t bytes_read = fread(buffer, sizeof(*buffer), sizeof(buffer) / sizeof(*buffer), file_stream);
    // Upon successful completion, fread() shall return the number of elements
    // successfully read which is less than nitems only if a read error or end-of-file is encountered.
    // If size or nitems is 0, fread() shall return 0 and the contents of the array and the state of the stream remain unchanged.
    // Otherwise, if a read error occurs, the error indicator for the stream shall be set, and errno shall be set to indicate the error.
    // (Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/fread.html).
    if (bytes_read < sizeof(buffer) / sizeof(*buffer) &&
        ferror(file_stream) != 0) {
        // Error.
        return;
    }

    if (SendAllBytes(socket, buffer, bytes_read) != 0) {
        // Error.
        return;
    }
}

int SendAllBytes(int socket, const char *buffer, size_t bytes_to_send)
{
    size_t total_bytes_sent = 0;
    while (bytes_to_send > 0) {
        const ssize_t bytes_sent = send(socket, &buffer[total_bytes_sent], bytes_to_send, 0);
        // Upon successful completion, send() shall return the number of bytes sent.
        // Otherwise, -1 shall be returned and errno set to indicate the error.
        // (Source: http://pubs.opengroup.org/onlinepubs/9699919799/).
        if (bytes_sent == -1) {
            // Error.
            return -1;
        }

        total_bytes_sent += bytes_sent;
        bytes_to_send -= bytes_sent;
    }
    return 0;
}

可移植性说明

考虑使用固定宽度整数类型来增强可移植性。在所描述的情况下,文件大小不是由固定宽度整数类型表示的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接