跨进程通信的内存映射文件实现

内存映射文件(Memory Mapped File,MMF)是一种允许多个进程共享内存区域的技术,这使得进程间的数据共享变得简单而高效。本文将介绍如何使用内存映射文件实现跨进程通信,并提供C++和C#的示例代码。

内存映射文件简介

内存映射文件是一种文件系统对象,它允许文件内容直接映射到进程的地址空间。这样,进程就可以像访问内存一样访问文件内容,而不需要进行常规的文件I/O操作。内存映射文件不仅可以提高文件访问速度,还可以实现进程间的数据共享。

跨进程通信示例

以下是一个使用内存映射文件实现跨进程通信的示例。这个示例包括一个C++编写的DLL库和一个C#的客户端程序。

C++DLL库定义了两个函数:SetValue和GetValue,分别用于设置和获取内存映射文件中的数据。

#include "stdafx.h" #include "sharedmem.h" #include "tchar.h" #include "stdio.h" extern HANDLE m_hFileMMF, m_pViewMMFFile, hMutex; class CMutex { public: CMutex() { if (!hMutex) { hMutex = CreateMutex(NULL, FALSE, L"Global\\MMFMutex"); } WaitForSingleObject(hMutex, INFINITE); } ~CMutex() { ReleaseMutex(hMutex); } }; void SetRecordCount(int value) { TCHAR* record = (TCHAR*)m_pViewMMFFile; swprintf_s(record, MAX_PATH, L"RECCNT=%d#", value); } extern "C" int GetRecordCount() { TCHAR* record = (TCHAR*)m_pViewMMFFile; TCHAR temp[MAX_PATH]; int recordCount = -1; TCHAR seps[] = L"=#"; TCHAR *token1 = NULL; TCHAR *next_token1 = NULL; _tcscpy_s(temp, MAX_PATH, record); token1 = _tcstok_s(temp, seps, &next_token1); if (token1 && _tcscmp(token1, _T("RECCNT")) == 0) { token1 = _tcstok_s(NULL, seps, &next_token1); recordCount = _ttoi(token1); } else { recordCount = 1; SetRecordCount(1); } return recordCount; } int nRecordCount = -1; void RemoveValue(TCHAR* key) { TCHAR* record = (TCHAR*)m_pViewMMFFile; TCHAR temp[MAX_PATH]; nRecordCount = GetRecordCount(); record += MAX_PATH; bool isRecordFound = false; for (int i = 1; i < nRecordCount; i++, record += MAX_PATH) { TCHAR seps[] = L"=#"; TCHAR *token1 = NULL; TCHAR *next_token1 = NULL; _tcscpy_s(temp, MAX_PATH, record); token1 = _tcstok_s(temp, seps, &next_token1); if (_tcscmp(token1, key) == 0) { isRecordFound = true; break; } } for (; i < nRecordCount - 1; i++, record += MAX_PATH) { TCHAR* nextRecord = record + MAX_PATH; _tcscpy_s(record, MAX_PATH, nextRecord); } } TCHAR* IfExists(TCHAR* key, TCHAR** value = NULL) { TCHAR* record = (TCHAR*)m_pViewMMFFile; TCHAR temp[MAX_PATH]; nRecordCount = GetRecordCount(); record += MAX_PATH; for (int i = 1; i < nRecordCount; i++, record += MAX_PATH) { TCHAR seps[] = L"=#"; TCHAR *token1 = NULL; TCHAR *next_token1 = NULL; _tcscpy_s(temp, MAX_PATH, record); token1 = _tcstok_s(temp, seps, &next_token1); if (_tcscmp(token1, key) == 0) { token1 = _tcstok_s(NULL, seps, &next_token1); if (value != NULL) { int len = _tcslen(token1) + 1; *value = new TCHAR(len); _tcscpy_s(*value, len, token1); } return record; } } return NULL; } extern "C" TCHAR* GetValue(TCHAR* key) { TCHAR* sRetVal = new TCHAR[MAX_PATH]; CMutex mutex; TCHAR* data = NULL; if (m_pViewMMFFile) { IfExists(key, &data); } return data; } extern "C" void SetValue(TCHAR* key, TCHAR* value) { CMutex mutex; if (m_pViewMMFFile) { if (value == NULL) { RemoveValue(key); } else { TCHAR* data = IfExists(key); if (data == NULL) { data = new TCHAR[MAX_PATH]; swprintf_s(data, MAX_PATH, L"%s=%s#", key, value); TCHAR* record = (TCHAR*)m_pViewMMFFile; record += MAX_PATH * nRecordCount; nRecordCount++; SetRecordCount(nRecordCount); _tcscpy_s(record, MAX_PATH, data); delete data; } else { swprintf_s(data, MAX_PATH, L"%s=%s#", key, value); } } } }

C#客户端程序通过P/Invoke调用C++DLL库中的函数,实现跨进程通信

using System; using System.Runtime.InteropServices; class Program { [DllImport("sharedmem.dll")] extern static int GetRecordCount(); [DllImport("sharedmem.dll")] extern static void SetValue(string key, string value); [DllImport("sharedmem.dll")] extern static IntPtr GetValue(string key); static void Main(string[] args) { Console.WriteLine("Setting value..."); SetValue("key1", "value1"); Console.WriteLine("Getting value..."); IntPtr intPtr = GetValue("key1"); string value = Marshal.PtrToStringUni(intPtr); Console.WriteLine($"Value: {value}"); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485