文件传输仅在服务器断开连接时完成

时间:2013-07-15 23:53:52

标签: c linux file transfer

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

如果服务器没有断开连接,那么传输不会完成客户端,并且客户端继续等待字节并且不会正确地突破循环(当fr_block_sz == 0时),因为它确实当服务器在收到文件后断开连接。它无休止地坐在循环中。

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

编辑:Per 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");

CONSOLE OUTPUT:

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。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

  1. 假设在服务器和客户端中,任何通信的前4个字节都是文件的大小。服务器为每个建立的连接发送前4个字节,直到文件完全发送。对于另一个文件/连接,服务器将再次发送4个字节来告诉文件大小。
  2. 因此,客户端的前4个字节将准确指示它必须处理多少数据。
  3. 客户端最初只读取4个字节而不是假设完整缓冲区,因为数据将4个字节转换为整数,以便它可以获得接收的确切字节数。不需要确认字节,在这里使用它是没用的。
  4. 一旦收到的字节等于服务器发送的字节,就会收到文件,服务器可以关闭连接。
  5. 您可以在接收文件中的字节数后假设下一个字节作为服务器准备发送另一个文件的指示符,或者如果您想要在每个连接中接收一个文件,那么如果您在缓冲区中接收到额外的字节,则只丢弃它。
  6. 可以有其他方式接收文件,我们有时会在下载管理器中看到。比如打破块中的文件或使用相同的连接接收多个文件,但我相信一旦你设置了协议,就可以轻松搞清楚增强功能。

    希望它有所帮助。

    只丢弃超过文件大小的任何字节。在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。

    此致 Kajal