0

我对下面的代码有一些问题。它旨在从服务器接收文件。只要服务器在发送后断开连接,它就可以 100% 正常工作。

如果服务器没有断开连接,则客户端的传输没有完成,客户端继续等待字节并且没有正确地跳出循环(当 fr_block_sz == 0 时),就像在服务器时一样收到文件后断开连接。它无休止地坐在循环中。

我希望能够接收文件并在之后保持连接打开。有什么建议吗?谢谢。

编辑:根据 Casey 的建议,我现在正在监视通过下面注释的代码写入的字节数,但出现了导致文件传输无法正确完成的奇怪行为。任何人都可以在我的代码中看到任何错误吗?谢谢。

编辑 2:我已经发布了关于我的问题的调试信息,以使其更清楚。

// Reciever of file (client)
int TotalSize = 7374; // hardcoded file size to expect
int FileSize = 0; // counter
int fr_block_sz = 0; 
while ((fr_block_sz = recv(sd, revbuf, 1, 0)) > 0)  //LENGTH == 512
{
    if (fr_block_sz < 0)
        if (errno == EAGAIN)
            continue;
        else
            printf("File write failed");

        if (fr_block_sz == 0)           
            break; //done

        // edit based on comment - does not change behavior
        if(FilzeSize > TotalSize)
        {
            fr_block_sz = fr_block_sz - (FileSize - TotalSize);   
        }            

        int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
        // add total bytes recvd every loop
        FileSize += write_sz;
        // if bytes recieved equals expect file size, break
        if (FileSize >= TotalSize)// this is where my problem is, as sometimes 
                                  // FileSize == 7376 or 7672 instead of 7374
                                  // When it fails, fr_block_sz == 24 which
                                  // i don't think is right either. Even when
                                  // set to break if FileSize > TotalSize, the 
                                  // loop still doesn't complete
            break;
        printf("Recieved size == %i of %i \n", FilzeSize, TotalSize);

        if (write_sz < fr_block_sz)
        {
            printf("File write failed");
        }

        bzero(revbuf, 1);

}
printf("Transfer complete \n");

控制台输出:

Recieved size == 512 of 7374 
Recieved size == 1024 of 7374 
Recieved size == 1368 of 7374 
Recieved size == 1880 of 7374 
Recieved size == 2392 of 7374 
Recieved size == 2736 of 7374 
Recieved size == 3248 of 7374 
Recieved size == 3760 of 7374 
Recieved size == 4104 of 7374 
Recieved size == 4616 of 7374 
Recieved size == 5128 of 7374 
Recieved size == 5472 of 7374 
Recieved size == 5984 of 7374 
Recieved size == 6496 of 7374 
Recieved size == 6840 of 7374 
Recieved size == 7352 of 7374 
Recieved size == 7376 of 7374 

一旦它到达这里,客户端将永远在循环中等待,并且没有任何反应。然后我必须从控制台手动停止程序,在程序停止后,只写入了 4096 字节的文件。如果有人能阐明我的问题,或者用“正常”的方式来解决这个问题,我将不胜感激。谢谢你。

编辑 - 固定(有点)。我找到了一种让它每次都能 100% 可靠工作的方法,那就是通过更改 LENGTH == 1,因此设置一个字节的缓冲区大小,如果内核正在逐字节写入,则无法获得短/长读取. 这可行,但显然不是最快的解决方案。我仍然想听听其他人的意见,并感谢您对 Rajal 的帮助。

4

2 回答 2

1

您的问题是,如果服务器没有关闭连接,您的客户端不知道文件传输何时完成。你怎么能传达这个事实?

于 2013-07-16T00:04:15.847 回答
1

我建议在客户端和服务器之间遵循一些协议。我可以显示如下示例。

  1. 假设在服务器和客户端中,任何通信的前 4 个字节都是文件的大小。前 4 个字节由服务器为每个已建立的连接发送,直到文件完全发送。对于另一个文件 /conenction,服务器将再次发送 4 个字节来告知文件的大小。
  2. 因此,客户端的前 4 个字节将准确指示它必须处理多少数据。
  3. 客户端最初只会读取 4 个字节,而不是假设缓冲区已满,因为数据会将 4 个字节转换为整数,以便它可以获取要接收的确切字节数。不需要确认字节,在这里有它是没有用的。
  4. 一旦接收到的字节等于服务器发送的字节,则假定文件已接收并且服务器可以关闭连接。
  5. 您可以在接收到文件中的字节数后假设下一个字节作为服务器已准备好发送另一个文件的指示符,或者如果您希望每个连接接收一个文件,那么如果您在缓冲区中收到额外的字节,只需丢弃它。

可以有其他方式来接收文件,就像我们有时在下载管理器中看到的那样。就像将文件分成块或使用相同的连接接收多个文件,但我相信一旦您设置了协议,就可以轻松找出增强功能。

希望能帮助到你。

只需丢弃超过文件大小的任何字节。在 fwrite 之前尝试以下操作。

    if(FilzeSize > TotalSize)
    {
        fr_block_sz = fr_block_sz - (FilezeSize - TotalSize);   
    }
    int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);

它应该写入不包括最后 2 个字节的 revbuf。

问候卡哈尔

于 2013-07-16T04:42:20.047 回答