进程间通信 - 二进制数据/序列化对象

时间:2014-05-04 17:14:29

标签: c++ ipc

我目前在同一台计算机上运行两个进程,一个'生产者'以及负责显示数据的Qt应用程序。这两个需要交换二进制数据(字节数组,序列化对象)。数据'包裹'可以从几个字节到几十个MB的大小不等。

这是一个简单而优雅的方法吗?

我考虑使用boost :: asio和Google Protocol Buffers,共享内存区域或只是低级套接字来实现这一点,但我有兴趣了解我可能忽略的其他解决方案。

性能并非绝对关键,但必须具有良好的延迟(<1秒)和带宽(比如说,> 5MB /秒)。

提前致谢!

1 个答案:

答案 0 :(得分:1)

如果您不喜欢额外的库,那么您可以尝试以下方法:

#if defined _WIN32 || defined _WIN64
    #include <windows.h>
#else
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <dlfcn.h>
    #include <fcntl.h>
    #include <unistd.h>
#endif

#include <cstdint>


typedef struct
{
    #if defined _WIN32 || defined _WIN64
    void* hFileMap;
    #else
    int hFileMap;
    #endif
    void* pData;
    size_t size;
} MemoryMap;

void* CreateMemoryMap(MemoryMap* info, const char* MapName, unsigned int size)
{
    #if defined _WIN32 || defined _WIN64
    info->hFileMap = NULL;
    info->pData = NULL;
    info->size = 0;

    if ((info->hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, MapName)) == NULL)
    {
        return NULL;
    }

    if ((info->pData = MapViewOfFile(info->hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, size)) == NULL)
    {
        CloseHandle(info->hFileMap);
        return NULL;
    }

    #else

    info->hFileMap = NULL;
    info->pData = NULL;
    info->size = 0;

    if ((info->hFileMap = open(MapName, O_RDWR | O_CREAT, 438)) == -1)
    {
        return NULL;
    }

    if ((info->pData = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hFileMap, 0)) == MAP_FAILED)
    {
        close(hFileMap);
        return NULL;
    }
    #endif

    info->size = size;
    return info->pData;
}

void* OpenMemoryMap(MemoryMap* info, const char* MapName, unsigned int size)
{
    #if defined _WIN32 || defined _WIN64
    info->hFileMap = NULL;
    info->pData = NULL;
    info->size = 0;

    if ((info->hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, MapName)) == NULL)
    {
        return NULL;
    }

    if ((info->pData = MapViewOfFile(info->hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, size)) == NULL)
    {
        CloseHandle(info->hFileMap);
        return NULL;
    }

    #else

    info->hFileMap = NULL;
    info->pData = NULL;
    info->size = 0;

    if ((info->hFileMap = open(MapName, O_RDWR | O_CREAT, 438)) == -1)
    {
        return NULL;
    }

    if ((info->pData = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hFileMap, 0)) == MAP_FAILED)
    {
        close(info->hFileMap);
        return NULL;
    }
    #endif

    info->size = size;
    return info->pData;
}

void CloseMap(MemoryMap* data)
{
    #if defined _WIN32 || defined _WIN64
    UnmapViewOfFile(data->pData);
    CloseHandle(data->hFileMap);
    #else
    munmap(data->pData, data->size);
    close(data->hFileMap);
    #endif
}



template<typename T>
class CAllocator
{
    private:
        size_t size;
        void* data = nullptr;

    public:
        typedef T* pointer;
        typedef const T* const_pointer;

        typedef T& reference;
        typedef const T& const_reference;

        typedef size_t size_type;
        typedef ptrdiff_t difference_type;

        typedef T value_type;


        CAllocator() {}
        CAllocator(void* data_ptr, size_type max_size) noexcept : size(max_size), data(data_ptr) {};

        template<typename U>
        CAllocator(const CAllocator<U>& other) noexcept {};

        CAllocator(const CAllocator &other) : size(other.size), data(other.data) {}

        template<typename U>
        struct rebind {typedef CAllocator<U> other;};

        pointer allocate(size_type n, const void* hint = 0) {return static_cast<pointer>(data);}
        void deallocate(void* ptr, size_type n) {}
        size_type max_size() const {return size / sizeof(T);}
};

template <typename T, typename U>
inline bool operator == (const CAllocator<T>&, const CAllocator<U>&) {return true;}

template <typename T, typename U>
inline bool operator != (const CAllocator<T>& a, const CAllocator<U>& b) {return !(a == b);}



/** Test case **/
#include <vector>
#include <iostream>
#include <stdexcept>

int main()
{
    /** Sender **/
    MemoryMap data = {0};
    if (!CreateMemoryMap(&data, "MapName", 1024))
    {
        if (!OpenMemoryMap(&data, "MapName", 1024))
        {
            throw std::runtime_error("Cannot map memory.");
        }
    }

    std::vector<int, CAllocator<int>> shared_sender_vector(CAllocator<int>(data.pData, data.size));
    shared_sender_vector.push_back(10);

    for (int i = 0; i < 10; ++i)
    {
        shared_sender_vector.push_back(i + 1);
    }



    /** Receiver **/


    MemoryMap data2 = {0};
    if (!CreateMemoryMap(&data2, "MapName", 1024))
    {
        if (!OpenMemoryMap(&data2, "MapName", 1024))
        {
            throw std::runtime_error("Cannot map memory.");
        }
    }


    int* offset = static_cast<int*>(data2.pData);
    std::vector<int, CAllocator<int>> shared_receiver_vector(CAllocator<int>(++offset, data2.size));
    shared_receiver_vector.reserve(*(--offset));

    for (int i = 0; i < 10; ++i)
    {
        std::cout<<shared_receiver_vector[i]<<" ";
    }

    CloseMap(&data);
    CloseMap(&data2);
}

打印:

1 2 3 4 5 6 7 8 9 10

可用于字符串和接受分配器的各种容器。它们将数据直接存储在共享内存映射中。分配器与我写的那个相同:

Boost Pool experience requested. Is it useful as allocator with preallocation?所以它可以重复用于你想要的任何东西..