我目前在同一台计算机上运行两个进程,一个'生产者'以及负责显示数据的Qt应用程序。这两个需要交换二进制数据(字节数组,序列化对象)。数据'包裹'可以从几个字节到几十个MB的大小不等。
这是一个简单而优雅的方法吗?
我考虑使用boost :: asio和Google Protocol Buffers,共享内存区域或只是低级套接字来实现这一点,但我有兴趣了解我可能忽略的其他解决方案。
性能并非绝对关键,但必须具有良好的延迟(<1秒)和带宽(比如说,> 5MB /秒)。
提前致谢!
答案 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?所以它可以重复用于你想要的任何东西..