使用 C++ 通过 TCP 发送文件,接收错误的大小

Posted

技术标签:

【中文标题】使用 C++ 通过 TCP 发送文件,接收错误的大小【英文标题】:Sending files over TCP using C++, recving wrong size 【发布时间】:2020-04-16 08:54:07 【问题描述】:

我对套接字编程非常陌生,我正在尝试通过 TCP 连接发送但很少出错。

这是我的代码

        FILE* File;
        char* Buffer;
        unsigned long Size;

        File = fopen("C:\\test.zip", "rb");
        if (!File)
        
            printf("Error while readaing the file\n");
            return;
        
        // file size 1
        fseek(File, 0, SEEK_END);
        Size = ftell(File);
        fseek(File, 0, SEEK_SET);


        Buffer = new char[Size]; 

        fread(Buffer, Size, 1, File);
        char cSize[MAX_PATH];
        sprintf(cSize, "%i", Size);

        cout << "MAX PATH " << MAX_PATH<<endl;
        cout << "cSize: " << cSize << endl;
        fclose(File);

` 所以这是为了找到我的文件的大小。我在这里尝试从其他问题中尝试的大部分代码,但它并没有解决我的问题。 ' 我的发送和接收:

unsigned long filechunk = 1025;

unsigned long byteSent = 0;
unsigned long bytesToSend = 0;

send(Sub, cSize, MAX_PATH, 0); // File size to client

while (byteSent < Size) 

    if ((Size - byteSent) >= filechunk) 
        bytesToSend = filechunk;
    
    else 
        bytesToSend = Size - byteSent;
    
    if (send(Sub, Buffer + byteSent, bytesToSend, 0)) 
        std::cout << "Sent: ";
    
    byteSent += bytesToSend;
    std::cout << "Size : "<<Size<<"    BytesSent : "<<byteSent<<"   Bytes to send: " << bytesToSend << std::endl;
    system("pause");

在客户端:

int Size;
char* Filesize = new char[5000000]; // is there a better way? my sfiles size are unknown but at least 50mb

if (recv(Socket, Filesize, 5000000, 0)) // File size

    Size = atoi((const char*)Filesize);
    printf("File size: %d\n", Size);


char* Buffer = new char[Size];
FILE* File;
File = fopen("test.zip", "wb"); //start copying from the server, creating the file first.
std::string convert;
long conv;

std::cout << "Size: " << Size << std::endl;

int total=Size;
int byteRecv = 0;
int recvCheck;
int bytes = 1025;

//getting the file
while (byteRecv < Size ) 

    recvCheck = recv(Socket, Buffer, bytes, 0);
    if (recvCheck >0) // File
    
        fwrite(Buffer, 1, byteRecv, File);

        std::cout << "Recieved:" << byteRecv << std::endl;

        Size -= byteRecv;
        byteRecv += byteRecv;
        std::cout << "Error: " << WSAGetLastError();
    
    else 
        std::cout << "Error: " << WSAGetLastError();
        total += 1; // the loop often get into infinit loop so i force it in case of this error.
        if (total > 3) 
            break;
        
    

fclose(File);

所以,我知道这不是很有效,我不确定是否有类似的问题,因为我已经在这里挖掘了几个星期。

-有没有更好的方法可以制作 char*[]?因为我还不知道要发送的文件的大小。 - ftell() 和 sifeof() 的工作方式相同吗? - 当我检查我从服务器接收的大小时,它是错误的。例如:服务器文件:32633513,recv 大小:3263 - 我从其他问题中提取的大部分代码并将其组合在一起。如果您看到任何不需要的东西,请告诉我,以便我记录下来。

【问题讨论】:

TCP 是流式协议;任何recv 可能只得到一个字节,或者全部,或者介于两者之间的任何数量。 (并不是一个recv 收到一个send 发送的内容。) 另外,byteRecv 从零开始,然后随着每个成功的recv 加倍,所以它永远不会是零。 【参考方案1】:

有很多错误的地方,但一开始可能会纠正你的问题:

在客户端替换(您都在减少字节总数和接收到的错误值):

Size -= byteRecv;
byteRecv += byteRecv;

与:

byteRecv += recvCheck; // actualizes the count of received bytes

另一个问题是您的缓冲区大小。永远不要试图在内存中获取整个文件,这通常是无稽之谈;文件通常由块管理。由于您在每个循环中最多读取 1025 个字节,因此只使用大小为 1025 的缓冲区,您不需要更多。阅读和写作都一样...

【讨论】:

谢谢你实际上解决了主要问题。但是现在除了错误传输文件的大小之外,还有更好的方法来检查接收的数据吗?例如:如果文件大小是 3000 并且我已经收到了 3050,那么会发生什么?对于我的程序,我接收了 6k 字节,尽管大小接收的实际值小于 4k 字节。 对于缓冲区,我可以改用大小为 1025 的缓冲区吗?它应该对整个文件进行相同的写入吗? 如果发送3000字节,则无法读取3050... 通常文件长度在开头发送,以便客户端知道。 更一般地说,您应该知道,tehre 不能保证字节的读取方式与发送方式相同,这意味着您需要,例如 N 个字节,您必须以循环(网络以块的形式传递字节)。 我明白了。所以在我发送文件大小之后,我的缓冲区不应该和文件大小一样大,但要大到足以接受发送的块?

以上是关于使用 C++ 通过 TCP 发送文件,接收错误的大小的主要内容,如果未能解决你的问题,请参考以下文章

通过 TCP 发送/接收文件 [重复]

036_python的大文件下载以及进度条展示

性能通过 TCP 套接字客户端-服务器应用程序发送/接收数据

TCP Socket在C#中接收数据错误

在 C++ 中通过 tcp 套接字发送结构

C++ 如何使用 Socket 类向 HTTP 服务器发送数据和接收响应