【问题标题】:Receiving a big file from socket floods memory, do I have a memory leak?从套接字接收一个大文件会淹没内存,我是否有内存泄漏?
【发布时间】:2020-03-16 10:46:38
【问题描述】:

我想将一个大文件从一台机器发送到另一台机器。所有字节都发送成功,另一端也收到了,但操作大量命中接收端的内存。内存使用量在几秒钟内以每秒约 400MB 的速度上升,然后又稳定下来。我测试的文件大小约为 7 gigs。

这是我用来从套接字读取到文件中的代码:

size_t recv_file(int socket, std::filesystem::path& dest_file) {
    uint64_t bytes_to_read = recv_byte_count(socket);
    char* const file_buffer = new char[MAX_BUFFER_FILE];
    size_t total_received{ 0 };

    try {
        std::fstream fs;
        fs.open(dest_file, std::fstream::in | std::fstream::out | std::fstream::app);

        while (bytes_to_read > 0) {
            const unsigned int actual_bytes_to_read = (bytes_to_read > MAX_BUFFER_FILE) ? MAX_BUFFER_FILE : bytes_to_read;

            size_t received = recv_raw(socket, file_buffer, actual_bytes_to_read, MAX_BUFFER_FILE);

            if (received > 0) {
                fs.write(file_buffer, received);
                bytes_to_read -= received;
                total_received += received;
                std::cout << "Bytes received: " << total_received << std::endl;
                memset(file_buffer, 0, MAX_BUFFER_FILE);


            } else throw WSA_socket_exception(WSAGetLastError(), socket);

        }

        fs.close();
        delete[] file_buffer;
    }
    catch (...) {
        delete[] file_buffer;
        return 0;
    }
    return total_received;
}


size_t recv_raw(const int socket, void* buffer, size_t bytes_to_read, int buffer_size = MAX_BUFFER) {
    char* ptr = static_cast<char*>(buffer);
    size_t received_total{ 0 };

    while (bytes_to_read > 0) {
        const int actual_bytes_to_read{ std::min(buffer_size, static_cast<int>(bytes_to_read)) };

        const int received = recv(socket, ptr, actual_bytes_to_read, 0);
        if (received == 0 || received < -1) throw connection_close_exception(socket);
        if (received > 0) {
            bytes_to_read -= static_cast<size_t>(received);
            ptr += received;
            received_total += static_cast<size_t>(received);
        }
    }
    return received_total;
}

【问题讨论】:

  • 您在示例中使用了 std::endl,这可能会产生一些同步副作用,有没有它的问题是否相同?
  • 虽然这很遗憾没有帮助,但我想了解为什么这会有所帮助
  • 作为标准 std::endl 刷新 std::cout 阻塞该线程直到它完成,这可能意味着 tcp 在发生这种情况时添加更多数据缓冲区。它可能会导致进程切换,如果不使用 std::ios_base::sync_with_stdio 可能需要与 stdio 同步。

标签: c++ sockets network-programming


【解决方案1】:

在从接收到最终写入文件的过程中,数据被复制了很多次。

tcp 和 file 都可能分配许多临时缓冲区,等待调用接收到的文件或(部分)刷新到文件系统的文件。 Tcp 由您的 tcp 设置控制,定义它可以分配多少,fs 中可能有类似的设置,否则您可以通过滚动您自己的 std::streambuf 子类来滚动自己的设置。

【讨论】:

  • 不过,这些都不应该分配 400MB。
猜你喜欢
  • 2015-08-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多