进程间通信-二进制数据/序列化对象 [英] Interprocess communication - Binary data/serialized objects
问题描述
我目前在同一台计算机上运行两个进程,一个生产者"和一个负责显示数据的Qt应用程序.这两个需要交换二进制数据(字节数组,序列化对象).数据包裹"的大小范围可以从几个字节到几十MB.
一种简单/优雅的方法是什么?
我曾考虑过使用boost :: asio和Google协议缓冲区,共享内存区域或只是低级套接字来实现这一目标,但是我对学习其他可能被我忽略的解决方案很感兴趣.
性能并不是绝对关键,但是适当的延迟(<1秒)和带宽(例如,> 5MB/秒)是必需的.
提前谢谢!
如果您不喜欢额外的库,则可以尝试以下操作:
#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
可用于字符串和接受分配器的各种容器.他们将数据直接存储在共享内存映射中.分配器与我为之分配的分配器相同:
需要提升池经验. 可以用作具有预分配功能的分配器吗?
I currently have two processes running on the same computer, a 'producer' and a Qt application tasked with displaying the data. These two need to exchange binary data (byte arrays, serialized objects). The data 'parcels' may range in size from a handful of bytes to tens of MBs.
What's a/the simple and elegant way to do this?
I thought about using boost::asio and Google Protocol Buffers, shared memory regions or just low-level sockets to achieve this, but I'm interested in learning about other solutions that I may have overlooked.
Performance is not absolutely critical but decent latency (<1 sec) and bandwidth (let's say, >5MB/sec) are necessary.
Thanks in advance!
If you don't like extra libraries then you can try the following:
#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);
}
It prints:
1 2 3 4 5 6 7 8 9 10
Can be used for strings and all sorts of containers that accepts allocators. They store their data directly in the shared-memory map. The allocator is the same as the one I wrote for:
Boost Pool experience requested. Is it useful as allocator with preallocation? so it can be reused for whatever you want..
这篇关于进程间通信-二进制数据/序列化对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!