简体   繁体   English

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

[英]Linux server, sending a file to windows client (Socket)

When i send the file to the client it gets corrupted, and with a size in bytes higher. 当我将文件发送到客户端时,它会被破坏,并且大小以字节为单位。

I have a version of this server running on Windows and works perfectly,but I'm not having the same result on Linux. 我有一个在Windows上运行的这个服务器的版本并且工作正常,但我在Linux上的结果并不相同。

The file size on disk may be the error in time to send the size in bytes to the client that runs on another platform? 磁盘上的文件大小可能是将大小以字节为单位发送到另一个平台上运行的客户端的错误?

the client side works perfectly, as I said I have a version of this server running on Windows, the only difference is in fread: Size = fread(mfcc, 1, min(sizeof(mfcc), FileSize), fp); 客户端工作正常,正如我所说我在Windows上运行此服务器的版本,唯一的区别在于fread: Size = fread(mfcc, 1, min(sizeof(mfcc), FileSize), fp);

fread function is being used correctly? fread功能正在正确使用?

an expert can analyze and help find the error? 专家可以分析并帮助找到错误吗?

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;
}

I think your problem is here: 我认为你的问题在这里:

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

You are sending Size_Send bytes with this call (most of which are miscellaneous memory from after the end of the Size_Send variable), rather than what you probably intended, which is to send sizeof(long) bytes. 您正在使用此调用发送Size_Send字节(大多数是在Size_Send变量结束之后的其他内存),而不是您可能想要的,即发送sizeof(长)字节。 Replace the second instance of Size_Sent in the above line with sizeof(long) and you'll get a better result. 用sizeof(long)替换上面一行中Size_Sent的第二个实例,你会得到更好的结果。

Assuming the POSIX sockets (IEEE Std 1003.1, 2013 Edition) are used. 假设使用POSIX套接字(IEEE Std 1003.1,2013版)

Analysis 分析

Let's consider the following pieces of code: 让我们考虑以下几段代码:

  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; } 

The send() function does not guarantee that all the data will be sent "at once" (ie with the single function call): send()函数不保证所有数据都会“立即”发送(即使用单个函数调用):

Return value 返回值

Upon successful completion, send() shall return the number of bytes sent. 成功完成后, send()将返回发送的字节数。 Otherwise, -1 shall be returned and errno set to indicate the error. 否则,返回-1并errno以指示错误。

send - send a message on a socket, The Open Group Base Specifications Issue 7, IEEE Std 1003.1, 2013 Edition . - 发送 - 在套接字上发送消息,Open Group Base Specifications Issue 7,IEEE Std 1003.1,2013 Edition

As a result, the if (send(client[iD].socket, Block, BytesRead, 0) != BytesRead) check does not seem to be right. 结果, if (send(client[iD].socket, Block, BytesRead, 0) != BytesRead)检查似乎不正确。

Solution

The return value of the send() function must be used to implement the loop to send all the bytes read previously by the fread() function call. 必须使用send()函数的返回值来实现循环,以发送fread()函数调用先前读取的所有字节。 Please see the implementation of the SendAllBytes() function. 请参阅SendAllBytes()函数的实现。 It should be used to correct the both pieces of code (see the "Analysis" section). 它应该用于纠正这两段代码(参见“分析”部分)。

The following code should be considered only as an example: 以下代码仅作为示例考虑:

#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;
}

Portability note 便携性说明

Consider using fixed-width integer types to enhance the portability. 考虑使用固定宽度整数类型来增强可移植性。 In the described case, the file size is not represented by the fixed-width integer type. 在所描述的情况下,文件大小不由固定宽度整数类型表示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM