如何将文件放入 boost::interprocess::managed_shared_memory 中?

2023-12-08

如何将任意名称和任意大小的文件放入boost::interprocess::managed_shared_memory?

注意,我的意思不是boost::interprocess::managed_mapped_file or boost::interprocess::file_mapping.

I chose managed_shared_memory因为其他选项需要固定的文件名 需要指定,但我需要传输具有不同名称的文件。

我需要使用 boost,而不是 Win32 API。

我在网上翻遍了海量的资料,却没有 找到任何合适的东西。

因此,我请求你的帮助。我将非常感谢你。


UPDATE

最后添加了奖励版本。现在这个答案提供了代码的三个完整版本:

  1. Using managed_shared_memory按照要求
  2. Using message_queue作为一种更自然的上传/传输方法
  3. 使用 TCP 套接字 (Asio) 来演示其灵活性

所有这些都仅使用Boost

共享内存管理段包含任意对象。所以你定义一个像这样的对象

 struct MyFile {
     std::string _filename;
     std::vector<char> _contents;
 };

并将其存储在那里。但是,等等,不要那么快,因为这些只能安全地存储在进程间分配器,所以添加一些魔法酱(又名很多有趣的 typedef 来声明分配器,以及一些构造函数):

namespace Shared {
    using Mem = bip::managed_shared_memory;
    using Mgr = Mem::segment_manager;

    template <typename T>
    using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;

    template <typename T> using Vector = bc::vector<T, Alloc<T>>;
    using String =
        bc::basic_string<char, std::char_traits<char>, Alloc<char>>;

    struct MyFile {
        using allocator_type = Alloc<char>;

        template <typename It>
        explicit MyFile(std::string_view name, It b, It e, allocator_type alloc)

        String _filename;
        Vector<char> _contents;
    };
}

现在您可以存储文件,例如:

Shared::Mem shm(bip::open_or_create, "shared_mem", 10ull << 30);

std::ifstream ifs("file_name.txt", std::ios::binary);
std::istreambuf_iterator<char> data_begin{ifs}, data_end{};

auto loaded = shm.find_or_construct<Shared::MyFile>("file1")(
        file.native(), data_begin, data_end,
         shm.get_segment_manager());

请注意,共享内存实际上不会立即占用 30GiB,即使 就是这样10ull << 30指定。在大多数操作系统上,这将是 稀疏分配,并且只有包含数据的页面才会被提交。

改善

您可能想知道什么是scoped_allocator_adaptor是为了。我们好像没用过吧?

嗯,我们的想法是not use find_or_construct直接每个文件,但要 存储一个Vector<MyFile这样您就可以利用 BIP 分配器的全部功能。

可以调用以下完整demo

  • 带有文件名参数,这些参数都将被加载(如果它们存在于 常规文件)
  • 不带参数,它将列出以前加载的文件

住在科里鲁

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp> // for COLIRU
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <fstream>
#include <filesystem>
#include <iostream>
#include <iomanip>

namespace bip = boost::interprocess;
namespace bc = boost::container;
namespace fs = std::filesystem;

namespace Shared {
#ifdef COLIRU
    using Mem = bip::managed_mapped_file; // managed_shared_memory not allows
#else
    using Mem = bip::managed_shared_memory;
#endif
    using Mgr = Mem::segment_manager;

    template <typename T>
    using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;

    template <typename T> using Vector = bc::vector<T, Alloc<T>>;
    using String = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;

    struct MyFile {
        using allocator_type = Alloc<char>;

        MyFile(MyFile&&) = default;
        MyFile(MyFile const& rhs, allocator_type alloc)
            : _filename(rhs._filename.begin(), rhs._filename.end(), alloc),
              _contents(rhs._contents.begin(), rhs._contents.end(), alloc) {}

        MyFile& operator=(MyFile const& rhs) {
            _filename.assign(rhs._filename.begin(), rhs._filename.end());
            _contents.assign(rhs._contents.begin(), rhs._contents.end());
            return *this;
        }

        template <typename It>
        explicit MyFile(std::string_view name, It b, It e, allocator_type alloc)
            : _filename(name.data(), name.size(), alloc),
              _contents(b, e, alloc) {}

        String _filename;
        Vector<char> _contents;

        friend std::ostream& operator<<(std::ostream& os, MyFile const& mf) {
            return os << "Name: " << std::quoted(mf._filename.c_str())
                      << " content size: " << mf._contents.size();
        }
    };
} // namespace Shared

int main(int argc, char** argv) {
    Shared::Mem shm(bip::open_or_create, "shared_mem", 512ull << 10);

    using FileList = Shared::Vector<Shared::MyFile>;
    auto& shared_files =
        *shm.find_or_construct<FileList>("FileList")(shm.get_segment_manager());

    if (1==argc) {
        std::cout << "Displaying previously loaded files: \n";
        for (auto& entry : shared_files)
            std::cout << entry << std::endl;
    } else {
        std::cout << "Loading files: \n";
        for (auto file : std::vector<fs::path>{argv + 1, argv + argc}) {
            if (is_regular_file(file)) {
                try {
                    std::ifstream ifs(file, std::ios::binary);
                    std::istreambuf_iterator<char> data_begin{ifs}, data_end{};

                    auto& loaded = shared_files.emplace_back(
                        file.native(), data_begin, data_end);

                    std::cout << loaded << std::endl;
                } catch (std::system_error const& se) {
                    std::cerr << "Error: " << se.code().message() << std::endl;
                } catch (std::exception const& se) {
                    std::cerr << "Other: " << se.what() << std::endl;
                }
            }
        }
    }
}

当运行时

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp -lrt -DCOLIRU
./a.out main.cpp a.out
./a.out

Prints

Loading files: 
Name: "main.cpp" content size: 3239
Name: "a.out" content size: 175176
Displaying previously loaded files: 
Name: "main.cpp" content size: 3239
Name: "a.out" content size: 175176

BONUS

针对评论,我认为值得进行实际比较

消息队列版本

为了进行比较,这里有一个消息队列实现

住在科里鲁

#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/endian/arithmetic.hpp>
#include <fstream>
#include <filesystem>
#include <iostream>
#include <iomanip>

namespace bip = boost::interprocess;
namespace fs = std::filesystem;
using bip::message_queue;
static constexpr auto MAX_FILENAME_LENGH = 512; // 512 bytes max filename length
static constexpr auto MAX_CONTENT_SIZE = 512ull << 10; // 512 KiB max payload size

struct Message {
    std::vector<char> _buffer;

    using Uint32 = boost::endian::big_uint32_t;
    struct header_t {
        Uint32 filename_length;
        Uint32 content_size;
    };
    static_assert(std::is_standard_layout_v<header_t> and
                  std::is_trivial_v<header_t>);

    Message() = default;

    Message(fs::path file) {
        std::string const name = file.native();
        std::ifstream ifs(file, std::ios::binary);
        std::istreambuf_iterator<char> data_begin{ifs}, data_end{};

        _buffer.resize(header_len + name.length());
        std::copy(begin(name), end(name), _buffer.data() + header_len);
        _buffer.insert(_buffer.end(), data_begin, data_end);
        header().filename_length = name.length();
        header().content_size    = size() - header_len - name.length();
    }

    Message(char const* buf, size_t size) 
        : _buffer(buf, buf+size) {}

    static constexpr auto header_len = sizeof(header_t);
    static constexpr auto max_size =
        header_len + MAX_FILENAME_LENGH + MAX_CONTENT_SIZE;

    char const* data() const { return _buffer.data(); } 
    size_t size() const      { return _buffer.size(); } 

    header_t& header() {
        assert(_buffer.size() >= header_len);
        return *reinterpret_cast<header_t*>(_buffer.data());
    }

    header_t const& header() const {
        assert(_buffer.size() >= header_len);
        return *reinterpret_cast<header_t const*>(_buffer.data());
    }

    std::string_view filename() const { 
        assert(_buffer.size() >= header_len + header().filename_length);
        return { _buffer.data() + header_len, header().filename_length };
    }

    std::string_view contents() const {
        assert(_buffer.size() >=
                header_len + header().filename_length + header().content_size);

        return {_buffer.data() + header_len + header().filename_length,
            header().content_size};
    }

    friend std::ostream& operator<<(std::ostream& os, Message const& mf) {
        return os << "Name: " << std::quoted(mf.filename())
                  << " content size: " << mf.contents().size();
    }
};

int main(int argc, char** argv) {
    message_queue mq(bip::open_or_create, "file_transport", 10, Message::max_size);

    if (1==argc) {
        std::cout << "Receiving uploaded files: \n";
        char rawbuf [Message::max_size];
        while (true) {
            size_t n;
            unsigned prio;
            mq.receive(rawbuf, sizeof(rawbuf), n, prio);

            Message decoded(rawbuf, n);
            std::cout << "Received: " << decoded << std::endl;
        }
    } else {
        std::cout << "Loading files: \n";
        for (auto file : std::vector<fs::path>{argv + 1, argv + argc}) {
            if (is_regular_file(file)) {
                try {
                    Message encoded(file);
                    std::cout << "Sending: " << encoded << std::endl;

                    mq.send(encoded.data(), encoded.size(), 0);
                } catch (std::system_error const& se) {
                    std::cerr << "Error: " << se.code().message() << std::endl;
                } catch (std::exception const& se) {
                    std::cerr << "Other: " << se.what() << std::endl;
                }
            }
        }
    }
}

A demo:

enter image description here

请注意,此方法存在文件大小限制,因为消息具有最大长度

TCP 套接字版本

这是一个 TCP 套接字实现。

住在科里鲁

#include <boost/asio.hpp>
#include <boost/endian/arithmetic.hpp>
#include <vector>
#include <fstream>
#include <filesystem>
#include <iostream>
#include <iomanip>

namespace fs = std::filesystem;
using boost::asio::ip::tcp;
using boost::system::error_code;
static constexpr auto MAX_FILENAME_LENGH = 512; // 512 bytes max filename length
static constexpr auto MAX_CONTENT_SIZE = 512ull << 10; // 512 KiB max payload size

struct Message {
    std::vector<char> _buffer;

    using Uint32 = boost::endian::big_uint32_t;
    struct header_t {
        Uint32 filename_length;
        Uint32 content_size;
    };
    static_assert(std::is_standard_layout_v<header_t> and
                  std::is_trivial_v<header_t>);

    Message() = default;

    Message(fs::path file) {
        std::string const name = file.native();
        std::ifstream ifs(file, std::ios::binary);
        std::istreambuf_iterator<char> data_begin{ifs}, data_end{};

        _buffer.resize(header_len + name.length());
        std::copy(begin(name), end(name), _buffer.data() + header_len);
        _buffer.insert(_buffer.end(), data_begin, data_end);
        header().filename_length = name.length();
        header().content_size    = actual_size() - header_len - name.length();
    }

    Message(char const* buf, size_t size) 
        : _buffer(buf, buf+size) {}

    static constexpr auto header_len = sizeof(header_t);
    static constexpr auto max_size =
        header_len + MAX_FILENAME_LENGH + MAX_CONTENT_SIZE;

    char const* data() const { return _buffer.data(); }
    size_t actual_size() const { return _buffer.size(); }
    size_t decoded_size() const {
        return header().filename_length + header().content_size;
    }
    bool is_complete() const {
        return actual_size() >= header_len && actual_size() >= decoded_size();
    }

    header_t& header() {
        assert(actual_size() >= header_len);
        return *reinterpret_cast<header_t*>(_buffer.data());
    }

    header_t const& header() const {
        assert(actual_size() >= header_len);
        return *reinterpret_cast<header_t const*>(_buffer.data());
    }

    std::string_view filename() const { 
        assert(actual_size() >= header_len + header().filename_length);
        return std::string_view(_buffer.data() + header_len,
                                header().filename_length);
    }

    std::string_view contents() const {
        assert(actual_size() >= decoded_size());

        return std::string_view(_buffer.data() + header_len +
                                    header().filename_length,
                                header().content_size);
    }

    friend std::ostream& operator<<(std::ostream& os, Message const& mf) {
        return os << "Name: " << std::quoted(mf.filename())
                  << " content size: " << mf.contents().size();
    }
};

int main(int argc, char** argv) {
    boost::asio::io_context ctx;
    u_int16_t port = 8989;

    if (1==argc) {
        std::cout << "Receiving uploaded files: " << std::endl;
        tcp::acceptor acc(ctx, tcp::endpoint{{}, port});

        while (true) {
            auto s = acc.accept();
            std::cout << "Connection accepted from " << s.remote_endpoint() << std::endl;

            Message msg;
            auto buf = boost::asio::dynamic_buffer(msg._buffer);
            error_code ec;
            while (auto n = read(s, buf, ec)) {
                std::cout << "(read " << n << " bytes, " << ec.message() << ")" << std::endl;

                while (msg.is_complete()) {
                    std::cout << "Received: " << msg << std::endl;
                    buf.consume(msg.decoded_size() + Message::header_len);
                }
            }
            std::cout << "Connection closed" << std::endl;
        }
    } else {
        std::cout << "Loading files: " << std::endl;
        tcp::socket s(ctx);
        s.connect(tcp::endpoint{{}, port});

        for (auto file : std::vector<fs::path>{argv + 1, argv + argc}) {
            if (is_regular_file(file)) {
                try {
                    Message encoded(file);
                    std::cout << "Sending: " << encoded << std::endl;

                    write(s, boost::asio::buffer(encoded._buffer));
               } catch (std::system_error const& se) {
                    std::cerr << "Error: " << se.code().message() << std::endl;
                } catch (std::exception const& se) {
                    std::cerr << "Other: " << se.what() << std::endl;
                }
            }
        }
    }
}

Demo:

enter image description here

请注意,这如何轻松地扩展到更大的文件、单个连接中的多个文件,甚至如果需要,可以同时扩展到多个连接。它还不进行双缓冲,这提高了性能。 这就是为什么这种方法比任何其他方法更常见的原因。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将文件放入 boost::interprocess::managed_shared_memory 中? 的相关文章

  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 为什么这个字符串用AesCryptoServiceProvider第二次解密时不相等?

    我在 C VS2012 NET 4 5 中的文本加密和解密方面遇到问题 具体来说 当我加密并随后解密字符串时 输出与输入不同 然而 奇怪的是 如果我复制加密的输出并将其硬编码为字符串文字 解密就会起作用 以下代码示例说明了该问题 我究竟做错
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 游戏内的java.awt.Robot?

    我正在尝试使用下面的代码来模拟击键 当我打开记事本时 它工作正常 但当我打开我想使用它的游戏时 它没有执行任何操作 所以按键似乎不起作用 我尝试模拟鼠标移动和点击 这些动作确实有效 有谁知道如何解决这个问题 我发现这个问题 如何在游戏中使用
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 如何将 GIT 调用的输出获取到批处理脚本中的变量中?

    我有一个 git 命令来获取当前存储库的最新 SHA 如下所示 git log pretty format H n 1 我有一个 Windows 批处理脚本 我想按如下方式使用它 SET CURRENT SHA 但我不知道如何将从 git
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲

随机推荐