windows C++:进程间通信高及时性、安全、数据量大的通信方式(一)文件映 ...

打印 上一主题 下一主题

主题 541|帖子 541|积分 1623

       
目录
一、文件映射 (File Mapping)
1. 简单的介绍
2. 文件映射的优势
3. 必要用到的API
CreateFile
CreateFileMapping
MapViewOfFile
UnmapViewOfFile
CloseHandle
4. 安全性
二、文件映射底层原理
1. 文件系统与文件句柄
2. 创建文件映射对象
3. 内存管理器与捏造内存
4. 共享内存
5. 文件映射的拆解
关键数据结构和函数
底层调用流程图
三、父子进程间通信的示例
四、优、缺点总结
长处:
缺点:
总结
五、改进

sharedMemoryW.cpp:


        windows进程间通信是写多进程步伐的必修课,高及时性、安全、数据量大的通信方式是很必要的,今天我们来看看文件映射
一、文件映射 (File Mapping)

1. 简单的介绍

        文件映射通过将文件的部门或全部内容映射到一个或多个进程的捏造地址空间,使得这些进程可以像访问普通内存一样访问文件内容。这个过程涉及以下步骤:

  • 创建或打开文件:进程首先必要创建或打开一个文件。
  • 创建文件映射对象:通过调用 Windows API 函数 CreateFileMapping,创建一个文件映射对象。这个对象表现文件的映射视图。
  • 映射视图到内存:使用 MapViewOfFile 函数将文件映射对象的一个视图映射到进程的地址空间中。
2. 文件映射的优势


  • 高及时性:文件映射将文件内容直接映射到内存,镌汰了传统 I/O 操作的开销,实现了高效的数据访问。
  • 高安全性:可以通过设置文件和内存映射对象的权限来控制不同进程对文件的访问。
  • 处理大数据量:得当处理大数据量的文件,通过内存映射可以高效地举行读写操作。
  • 共享内存:在同一台计算机上的多个进程可以共享同一块内存,简化了进程间通信的复杂性。
3. 必要用到的API

CreateFile

        用于创建或打开一个文件。
  1. HANDLE CreateFile(
  2.     LPCSTR lpFileName,
  3.     DWORD dwDesiredAccess,
  4.     DWORD dwShareMode,
  5.     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  6.     DWORD dwCreationDisposition,
  7.     DWORD dwFlagsAndAttributes,
  8.     HANDLE hTemplateFile
  9. );
复制代码
参数:


  • lpFileName (LPCSTR): 文件名。
  • dwDesiredAccess (DWORD): 访问权限。常见值包罗 GENERIC_READ、GENERIC_WRITE 等。
  • dwShareMode (DWORD): 共享模式。常见值包罗 FILE_SHARE_READ、FILE_SHARE_WRITE 等。
  • lpSecurityAttributes (LPSECURITY_ATTRIBUTES): 安全属性指针,可为 NULL。
  • dwCreationDisposition (DWORD): 怎样创建文件。常见值包罗 CREATE_NEW、CREATE_ALWAYS、OPEN_EXISTING 等。
  • dwFlagsAndAttributes (DWORD): 文件属性和标志。常见值包罗 FILE_ATTRIBUTE_NORMAL、FILE_FLAG_OVERLAPPED 等。
  • hTemplateFile (HANDLE): 模板文件句柄,可为 NULL。
        为了确保文件映射的安全性,可以使用 Windows 的安全属性(SECURITY_ATTRIBUTES)来设置访问控制权限。如许可以限制哪些进程可以访问或修改映射的文件内容。
   为了确保文件映射的安全性,可以使用 Windows 的安全属性(SECURITY_ATTRIBUTES)来设置访问控制权限。这些安全属性答应您指定一个安全形貌符,该形貌符定义了哪些用户和组可以访问或修改映射的文件内容。以下是怎样使用 SECURITY_ATTRIBUTES 结构来设置访问控制权限的步骤:
  

  • 创建一个安全形貌符:使用 InitializeSecurityDescriptor 函数初始化一个安全形貌符。
  • 设置访问控制列表 (ACL):使用 SetSecurityDescriptorDacl 函数为安全形貌符设置一个访问控制列表 (ACL),定义访问权限。
  • 初始化 SECURITY_ATTRIBUTES 结构:将安全形貌符包含在 SECURITY_ATTRIBUTES 结构中。
  • 传递 SECURITY_ATTRIBUTES 结构:在调用 CreateFileMapping 或其他干系 API 时,将 SECURITY_ATTRIBUTES 结构传递给它们。
  1.     // 定义安全描述符字符串 (SDDL)
  2.     // 这里设置为允许所有用户读取和写入
  3.     LPCSTR sddl = "D:P(A;;GA;;;WD)";
  4.     // 创建一个安全描述符
  5.     PSECURITY_DESCRIPTOR pSD = NULL;
  6.     if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(sddl, SDDL_REVISION_1, &pSD, NULL)) {
  7.         // 处理错误
  8.         printf("ConvertStringSecurityDescriptorToSecurityDescriptorA 错误: %d\n", GetLastError());
  9.         return 1;
  10.     }
  11.     // 初始化 SECURITY_ATTRIBUTES 结构
  12.     SECURITY_ATTRIBUTES sa;
  13.     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  14.     sa.lpSecurityDescriptor = pSD;
  15.     sa.bInheritHandle = FALSE;
  16.     // 创建或打开文件
  17.     HANDLE hFile = CreateFile(
  18.         "example.txt",
  19.         GENERIC_READ | GENERIC_WRITE,
  20.         0,
  21.         &sa,  // 使用自定义的安全属性
  22.         CREATE_ALWAYS,
  23.         FILE_ATTRIBUTE_NORMAL,
  24.         NULL
  25.     );
复制代码
   关键点说明:
  

  • 安全形貌符字符串 (SDDL): 示例中的 SDDL "D(A;;GA;;;WD)" 设置了一个答应所有效户读取和写入的安全形貌符。您可以根据需求调整这个字符串以设置不同的权限。
  • ConvertStringSecurityDescriptorToSecurityDescriptorA: 将 SDDL 转换为实际的安全形貌符。
  • SECURITY_ATTRIBUTES: 包含了安全形貌符,用于设置文件和文件映射对象的安全属性。
  通过上述步骤和示例代码,您可以设置文件映射的安全属性,控制哪些进程可以访问或修改映射的文件内容。
          总之,文件映射是一种高效、机动的进程间通信机制,特别得当必要处理大块数据而且要求高及时性和高安全性的场景。通过合理的权限设置和内存管理,可以充分利用文件映射的优势,提高系统的整体性能。
CreateFileMapping

        用于创建一个文件映射对象。
  1. HANDLE CreateFileMapping(
  2.     HANDLE hFile,
  3.     LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
  4.     DWORD flProtect,
  5.     DWORD dwMaximumSizeHigh,
  6.     DWORD dwMaximumSizeLow,
  7.     LPCSTR lpName
  8. );
复制代码
参数:


  • hFile (HANDLE): 文件句柄。
  • lpFileMappingAttributes (LPSECURITY_ATTRIBUTES): 安全属性指针,可为 NULL。
  • flProtect (DWORD): 保护属性。常见值包罗 PAGE_READONLY、PAGE_READWRITE 等。
  • dwMaximumSizeHigh (DWORD): 映射文件的最大尺寸(高位)。
  • dwMaximumSizeLow (DWORD): 映射文件的最大尺寸(低位)。
  • lpName (LPCSTR): 文件映射对象的名字,可为 NULL。
返回值: 成功返回文件映射对象句柄,失败返回 NULL。

  1. HANDLE hFileMapping = CreateFileMapping(
  2.     hFile,
  3.     NULL,
  4.     PAGE_READWRITE,
  5.     0,
  6.     1024,
  7.     "Local\\MyFileMapping"
  8. );
  9. if (hFileMapping == NULL) {
  10.     // 处理错误
  11. }
复制代码
MapViewOfFile

        将文件映射对象的一个视图映射到进程的地址空间中。
  1. LPVOID MapViewOfFile(
  2.     HANDLE hFileMappingObject,
  3.     DWORD dwDesiredAccess,
  4.     DWORD dwFileOffsetHigh,
  5.     DWORD dwFileOffsetLow,
  6.     SIZE_T dwNumberOfBytesToMap
  7. );
复制代码
参数:


  • hFileMappingObject (HANDLE): 文件映射对象句柄。
  • dwDesiredAccess (DWORD): 访问权限。常见值包罗 FILE_MAP_READ、FILE_MAP_WRITE 等。
  • dwFileOffsetHigh (DWORD): 文件偏移量的高位。
  • dwFileOffsetLow (DWORD): 文件偏移量的低位。
  • dwNumberOfBytesToMap (SIZE_T): 映射的字节数。
 返回值: 成功返回映射视图的指针,失败返回 NULL。
  1. LPVOID lpBaseAddress = MapViewOfFile(
  2.     hFileMapping,
  3.     FILE_MAP_READ,
  4.     0,
  5.     0,
  6.     0
  7. );
  8. if (lpBaseAddress == NULL) {
  9.     // 处理错误
  10. }
复制代码

UnmapViewOfFile

        排除文件视图的映射。
  1. BOOL UnmapViewOfFile(
  2.     LPCVOID lpBaseAddress
  3. );
复制代码
  1. if (!UnmapViewOfFile(lpBaseAddress)) {
  2.     // 处理错误
  3. }
复制代码
CloseHandle

        关闭文件、文件映射对象或文件视图的句柄。
  1. BOOL CloseHandle(
  2.     HANDLE hObject
  3. );
复制代码
  1. if (!CloseHandle(hFile)) {
  2.     // 处理错误
  3. }
  4. if (!CloseHandle(hFileMapping)) {
  5.     // 处理错误
  6. }
复制代码
4. 安全性

        为了确保文件映射的安全性,可以使用 Windows 的安全属性(SECURITY_ATTRIBUTES)来设置访问控制权限。如许可以限制哪些进程可以访问或修改映射的文件内容。
        总之,文件映射是一种高效、机动的进程间通信机制,特别得当必要处理大块数据而且要求高及时性和高安全性的场景。通过合理的权限设置和内存管理,可以充分利用文件映射的优势,提高系统的整体性能。

二、文件映射底层原理

        在 Windows 底层,文件映射的实现涉及多个关键组件和机制,包罗内存管理器、文件系统、内核对象和捏造内存管理。以下是 Windows 底层实现文件映射的主要步骤和机制:
1. 文件系统与文件句柄

        当应用步伐调用 CreateFile 函数时,Windows 内核通过文件系统驱动步伐将文件打开并创建一个文件句柄。文件系统驱动步伐负责处理文件的底层访问,包罗读写操作、权限查抄和文件缓存。
2. 创建文件映射对象

        调用 CreateFileMapping 时,Windows 内核创建一个文件映射对象。这涉及到以下几个步骤:


  • 分配内核对象:Windows 内核分配一个内核对象来表现文件映射对象。这个对象包含文件的元数据、权限信息和映射视图的信息。
  • 建立文件与内存的关联:内核为文件映射对象分配一个区域,在文件和捏造内存之间建立关联。
3. 内存管理器与捏造内存

        当应用步伐调用 MapViewOfFile 时,Windows 内核的内存管理器开始工作:


  • 捏造地址空间:内存管理器为文件映射对象分配捏造地址空间。这个捏造地址空间是应用步伐可以访问的内存区域。
  • 页表:内存管理器更新进程的页表,将捏造地址映射到物理内存。假如物理内存不敷,内存管理器会将部门页面换出到分页文件。
  • 懒加载:文件内容不会立刻加载到内存。当进程访问映射视图时,内存管理器通过页错误机制将所需的文件内容加载到内存。
4. 共享内存

        多个进程可以通过文件映射对象共享内存。不同进程调用 OpenFileMapping 和 MapViewOfFile 来访问同一个文件映射对象:


  • 内核对象共享:文件映射对象在内核中是全局的,多个进程可以通过内核对象句柄访问同一文件映射对象。
  • 捏造地址空间独立:固然捏造地址空间在每个进程中是独立的,但它们都可以映射到相同的物理内存区域,这实现了内存共享。
5. 文件映射的拆解

        当进程调用 UnmapViewOfFile 时,内存管理器排除文件视图的映射:


  • 页表清理:内存管理器从进程的页表中移除映射条目,释放对应的捏造地址空间。
  • 引用计数:文件映射对象有一个引用计数,当所有进程都排除映射并关闭文件映射对象时,内核释放文件映射对象和干系的资源。
关键数据结构和函数



  • 文件映射对象:由 FILE_OBJECT 和 SECTION_OBJECT 数据结构表现。
  • 页表(Page Table):内存管理器使用页表来管理捏造地址到物理地址的映射。
  • 内存管理器函数:MmCreateSection、MmMapViewOfSection、MmUnmapViewOfSection 等函数用于管理文件映射的创建、映射息争除映射。
底层调用流程图

  1. graph TD;
  2.     A[应用程序] -->|调用 CreateFile| B[文件系统驱动]
  3.     B -->|返回文件句柄| A
  4.     A -->|调用 CreateFileMapping| C[内核]
  5.     C -->|创建文件映射对象| D[内存管理器]
  6.     D -->|建立文件与内存关联| C
  7.     A -->|调用 MapViewOfFile| D
  8.     D -->|分配虚拟地址空间| A
  9.     A -->|访问映射视图| D
  10.     D -->|通过页错误加载内容| E[物理内存]
  11.     A -->|调用 UnmapViewOfFile| D
  12.     D -->|解除映射视图| A
  13.     C -->|引用计数清零时释放资源| D
复制代码
三、父子进程间通信的示例

fileMap底子共享通信代码:
  1. #include <windows.h>
  2. #include <iostream>
  3. #include <string>
  4. #include <stdexcept>
  5. #include <memory>
  6. class SharedMemory {
  7. public:
  8.     SharedMemory(const std::wstring& name, size_t size);
  9.     ~SharedMemory();
  10.     bool create();
  11.     bool open();
  12.     void write(const std::wstring& data);
  13.     std::wstring read();
  14.     void close();
  15.     void signal();  // 用于通知另一个进程数据已写入
  16.     void wait();    // 用于等待另一个进程写入数据
  17. private:
  18.     std::wstring name_;
  19.     size_t size_;
  20.     HANDLE hFile_;
  21.     HANDLE hMapFile_;
  22.     LPVOID lpBase_;
  23.     HANDLE hEvent_;
  24.     void cleanup();
  25.     void checkAndThrow(bool condition, const std::wstring& errorMessage);
  26. };
  27. #include "sharedMemoryW.h"
  28. // 构造函数
  29. SharedMemory::SharedMemory(const std::wstring& name, size_t size)
  30.     : name_(name), size_(size), hFile_(NULL), hMapFile_(NULL), lpBase_(NULL), hEvent_(NULL) {}
  31. // 析构函数
  32. SharedMemory::~SharedMemory() {
  33.     close();
  34. }
  35. // 创建文件映射对象和事件对象
  36. bool SharedMemory::create() {
  37.     hFile_ = CreateFileW(name_.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  38.     checkAndThrow(hFile_ != INVALID_HANDLE_VALUE, L"Unable to create file.");
  39.     hMapFile_ = CreateFileMappingW(hFile_, NULL, PAGE_READWRITE, 0, static_cast<DWORD>(size_), name_.c_str());
  40.     checkAndThrow(hMapFile_ != NULL, L"Unable to create file mapping object.");
  41.     lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
  42.     checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
  43.     hEvent_ = CreateEventW(NULL, TRUE, FALSE, (name_ + L"_Event").c_str());
  44.     checkAndThrow(hEvent_ != NULL, L"Unable to create event object.");
  45.     return true;
  46. }
  47. // 打开现有的文件映射对象和事件对象
  48. bool SharedMemory::open() {
  49.     hMapFile_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name_.c_str());
  50.     checkAndThrow(hMapFile_ != NULL, L"Unable to open file mapping object.");
  51.     lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
  52.     checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
  53.     hEvent_ = OpenEventW(EVENT_ALL_ACCESS, FALSE, (name_ + L"_Event").c_str());
  54.     checkAndThrow(hEvent_ != NULL, L"Unable to open event object.");
  55.     return true;
  56. }
  57. // 写入数据到映射内存
  58. void SharedMemory::write(const std::wstring& data) {
  59.     if (lpBase_ != NULL) {
  60.         memcpy(lpBase_, data.c_str(), (data.size() + 1) * sizeof(wchar_t));  // 包括终止符
  61.         signal(); // 通知另一个进程数据已写入
  62.     }
  63. }
  64. // 读取数据从映射内存
  65. std::wstring SharedMemory::read() {
  66.     if (lpBase_ != NULL) {
  67.         return std::wstring(static_cast<wchar_t*>(lpBase_));
  68.     }
  69.     return L"";
  70. }
  71. // 关闭文件映射和事件对象
  72. void SharedMemory::close() {
  73.     cleanup();
  74. }
  75. // 用于通知另一个进程数据已写入
  76. void SharedMemory::signal() {
  77.     if (hEvent_ != NULL) {
  78.         SetEvent(hEvent_);
  79.     }
  80. }
  81. // 用于等待另一个进程写入数据
  82. void SharedMemory::wait() {
  83.     if (hEvent_ != NULL) {
  84.         WaitForSingleObject(hEvent_, INFINITE);
  85.     }
  86. }
  87. void SharedMemory::cleanup() {
  88.     if (lpBase_ != NULL) {
  89.         UnmapViewOfFile(lpBase_);
  90.         lpBase_ = NULL;
  91.     }
  92.     if (hMapFile_ != NULL) {
  93.         CloseHandle(hMapFile_);
  94.         hMapFile_ = NULL;
  95.     }
  96.     if (hFile_ != NULL) {
  97.         CloseHandle(hFile_);
  98.         hFile_ = NULL;
  99.     }
  100.     if (hEvent_ != NULL) {
  101.         CloseHandle(hEvent_);
  102.         hEvent_ = NULL;
  103.     }
  104. }
  105. void SharedMemory::checkAndThrow(bool condition, const std::wstring& errorMessage) {
  106.     if (!condition) {
  107.         DWORD errorCode = GetLastError();
  108.         throw std::runtime_error(std::string(errorMessage.begin(), errorMessage.end()) + " Error code: " + std::to_string(errorCode));
  109.     }
  110. }
复制代码
        父进程:
  1. #include <windows.h>
  2. #include <iostream>
  3. #include <string>
  4. #include "sharedMemoryW.h"
  5. void CreateChildProcess(const std::wstring& sharedMemoryName, size_t sharedMemorySize) {
  6.     STARTUPINFOW si;
  7.     PROCESS_INFORMATION pi;
  8.     ZeroMemory(&si, sizeof(si));
  9.     si.cb = sizeof(si);
  10.     ZeroMemory(&pi, sizeof(pi));
  11.     std::wstring commandLine = L"ChildProcess.exe " + sharedMemoryName + L" " + std::to_wstring(sharedMemorySize);
  12.     if (!CreateProcessW(NULL, &commandLine[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
  13.         std::wcerr << L"CreateProcess failed (" << GetLastError() << L")." << std::endl;
  14.         return;
  15.     }
  16.     CloseHandle(pi.hProcess);
  17.     CloseHandle(pi.hThread);
  18. }
  19. int main() {
  20.     const std::wstring sharedMemoryName = L"SharedMemoryExample";
  21.     const size_t sharedMemorySize = 1024;
  22.     SharedMemory sharedMemory(sharedMemoryName, sharedMemorySize);
  23.     try {
  24.         sharedMemory.create();
  25.     }
  26.     catch (const std::exception& e) {
  27.         std::cerr << "Error: " << e.what() << std::endl;
  28.         return 1;
  29.     }
  30.     CreateChildProcess(sharedMemoryName, sharedMemorySize);
  31.     std::wstring message = L"Hello from Parent Process";
  32.     sharedMemory.write(message);
  33.     std::wcout << L"Parent process waiting for child process to read the message..." << std::endl;
  34.     sharedMemory.wait();  // 等待子进程读取数据
  35.     std::wcout << L"Parent process read: " << sharedMemory.read() << std::endl;
  36.     sharedMemory.close();
  37.     system("pause");
  38.     return 0;
  39. }
复制代码


子进程:
  1. #include <windows.h>
  2. #include <iostream>
  3. #include <string>
  4. #include "sharedMemoryW.h" // 假设SharedMemory类的代码放在这个头文件中
  5. int wmain(int argc, wchar_t* argv[]) {
  6.     if (argc != 3) {
  7.         std::wcerr << L"Usage: ChildProcess <SharedMemoryName> <SharedMemorySize>" << std::endl;
  8.         return 1;
  9.     }
  10.     std::wstring sharedMemoryName = argv[1];
  11.     size_t sharedMemorySize = std::stoull(argv[2]);
  12.     SharedMemory sharedMemory(sharedMemoryName, sharedMemorySize);
  13.     try {
  14.         sharedMemory.open();
  15.     }
  16.     catch (const std::exception& e) {
  17.         std::cerr << "Error: " << e.what() << std::endl;
  18.         return 1;
  19.     }
  20.     std::wcout << L"Child process read: " << sharedMemory.read() << std::endl;
  21.     std::wstring response = L"Hello from Child Process";
  22.     sharedMemory.write(response);
  23.     std::wcout << L"Child process waiting for parent process to read the message..." << std::endl;
  24.     sharedMemory.signal();  // 通知父进程数据已写入
  25.     sharedMemory.close();
  26.     system("pause");
  27.     return 0;
  28. }
复制代码

更多代码请访问我的GitHub:
   GitHub - bowenliu1996/SharedMemoryW: Windows file mapping communication, including demo
  
四、优、缺点总结

长处:


  • 高效性:共享内存答应两个或多个进程直接访问同一块内存区域,制止了频仍的数据拷贝,提高了数据传输的速度。
  • 低耽误:共享内存通信是一种低耽误的通信方式,由于数据直接写入和读取内存,没有网络或其他中心前言的耽误。
  • 高吞吐量:由于直接内存访问,共享内存适用于必要传输大量数据的场景,可以实现高吞吐量的数据传输。
  • 机动性:共享内存可以用于各种类型的数据传输,无论是简单的字符串还是复杂的结构体。
缺点:


  • 复杂的同步机制:共享内存本身不提供同步机制,必要使用额外的同步本领(如互斥锁、事件等)来确保数据读写的精确性和一致性。这增长了开发的复杂性,容易引入竞态条件(Race Conditions)。
    深刻分析:同步标题是共享内存使用中的主要挑战之一。没有精确处理同步,大概导致数据竞争、死锁、饿死等标题。这些标题不仅难以调试,而且大概导致数据损坏或步伐瓦解。
  • 内存管理难度:必要显式地管理共享内存的分配和释放,容易导致内存泄漏或内存碎片化。
    深刻分析:内存管理错误是步伐员常犯的错误之一。在共享内存的场景中,内存泄漏不仅影响一个进程,还会影响到所有使用该共享内存的进程,大概导致系统资源耗尽。
  • 安全性标题:共享内存区域可以被所有拥有权限的进程访问,存在潜在的安全风险。假如没有严酷的访问控制,大概导致敏感数据泄漏或被恶意窜改。
    深刻分析:安全性标题尤其在多用户环境中显得突出。恶意进程可以利用共享内存中的数据举行攻击或窜改,这必要额外的措施来保护数据的完整性和机密性。
  • 平台依靠性:共享内存的实现通常依靠于操作系统的底层机制,不同操作系统(如Windows和Unix)的实现细节不同,导致代码的可移植性差。
    深刻分析:跨平台开发时,共享内存的实现必要针对不同平台举行适配。这增长了开发和维护成本,同时也大概导致在不同平台上出现难以预见的标题。
  • 调试困难:共享内存调试相对困难,由于多个进程同时操作同一内存区域,调试工具和技术支持较少。
    深刻分析:调试共享内存中的标题往往必要相识多个进程的状态和行为,这增长了调试的难度和复杂性。开发人员必要具备更高的调试本领和履历。
总结

        共享内存通信在高效数据传输方面有显着优势,但其复杂的同步机制、内存管理、安全性标题、平台依靠性和调试困难都是使用过程中必须慎重考虑的缺点。这些缺点不仅增长了开发和维护的难度,还大概带来潜在的系统稳定性和安全性风险。因此,在使用共享内存时,必要综合权衡其优缺点,选择得当具体应用场景的通信机制。

五、改进

        根据复杂的同步机制、内存管理难度、平台依靠性、安全性标题、调试困难等标题。
我们优化代码:
sharedMemoryW.h
  1. #include <windows.h>
  2. #include <iostream>
  3. #include <string>
  4. #include <stdexcept>
  5. #include <memory>
  6. class SharedMemory {
  7. public:
  8.     SharedMemory(const std::wstring& name, size_t size);
  9.     ~SharedMemory();
  10.     bool create();
  11.     bool open();
  12.     void write(const std::wstring& data);
  13.     std::wstring read();
  14.     void close();
  15.     void signal();  // 用于通知另一个进程数据已写入
  16.     void wait();    // 用于等待另一个进程写入数据
  17. private:
  18.     std::wstring name_;
  19.     size_t size_;
  20.     HANDLE hFile_;
  21.     HANDLE hMapFile_;
  22.     LPVOID lpBase_;
  23.     HANDLE hEvent_;
  24.     HANDLE hMutex_;  // 新增的互斥锁
  25.     void cleanup();
  26.     void checkAndThrow(bool condition, const std::wstring& errorMessage);
  27. };
复制代码


sharedMemoryW.cpp:

  1. #include "sharedMemoryW.h"
  2. // 构造函数
  3. SharedMemory::SharedMemory(const std::wstring& name, size_t size)
  4.     : name_(name), size_(size), hFile_(NULL), hMapFile_(NULL), lpBase_(NULL), hEvent_(NULL), hMutex_(NULL) {}
  5. // 析构函数
  6. SharedMemory::~SharedMemory() {
  7.     close();
  8. }
  9. // 创建文件映射对象和事件对象
  10. bool SharedMemory::create() {
  11.     SECURITY_ATTRIBUTES sa;
  12.     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  13.     sa.bInheritHandle = FALSE;
  14.     sa.lpSecurityDescriptor = NULL;  // 可以自定义安全描述符
  15.     hFile_ = CreateFileW(name_.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  16.     checkAndThrow(hFile_ != INVALID_HANDLE_VALUE, L"Unable to create file.");
  17.     hMapFile_ = CreateFileMappingW(hFile_, NULL, PAGE_READWRITE, 0, static_cast<DWORD>(size_), name_.c_str());
  18.     checkAndThrow(hMapFile_ != NULL, L"Unable to create file mapping object.");
  19.     lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
  20.     checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
  21.     hEvent_ = CreateEventW(&sa, TRUE, FALSE, (name_ + L"_Event").c_str());
  22.     checkAndThrow(hEvent_ != NULL, L"Unable to create event object.");
  23.     hMutex_ = CreateMutexW(&sa, FALSE, (name_ + L"_Mutex").c_str());
  24.     checkAndThrow(hMutex_ != NULL, L"Unable to create mutex object.");
  25.     return true;
  26. }
  27. // 打开现有的文件映射对象和事件对象
  28. bool SharedMemory::open() {
  29.     hMapFile_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name_.c_str());
  30.     checkAndThrow(hMapFile_ != NULL, L"Unable to open file mapping object.");
  31.     lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
  32.     checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
  33.     hEvent_ = OpenEventW(EVENT_ALL_ACCESS, FALSE, (name_ + L"_Event").c_str());
  34.     checkAndThrow(hEvent_ != NULL, L"Unable to open event object.");
  35.     hMutex_ = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, (name_ + L"_Mutex").c_str());
  36.     checkAndThrow(hMutex_ != NULL, L"Unable to open mutex object.");
  37.     return true;
  38. }
  39. // 写入数据到映射内存
  40. void SharedMemory::write(const std::wstring& data) {
  41.     WaitForSingleObject(hMutex_, INFINITE);  // 加锁
  42.     if (lpBase_ != NULL) {
  43.         memcpy(lpBase_, data.c_str(), (data.size() + 1) * sizeof(wchar_t));  // 包括终止符
  44.         signal(); // 通知另一个进程数据已写入
  45.         std::wcout << L"Data written: " << data << std::endl;  // 日志记录
  46.     }
  47.     ReleaseMutex(hMutex_);  // 解锁
  48. }
  49. // 读取数据从映射内存
  50. std::wstring SharedMemory::read() {
  51.     WaitForSingleObject(hMutex_, INFINITE);  // 加锁
  52.     std::wstring result;
  53.     if (lpBase_ != NULL) {
  54.         result = std::wstring(static_cast<wchar_t*>(lpBase_));
  55.         std::wcout << L"Data read: " << result << std::endl;  // 日志记录
  56.     }
  57.     ReleaseMutex(hMutex_);  // 解锁
  58.     return result;
  59. }
  60. // 关闭文件映射和事件对象
  61. void SharedMemory::close() {
  62.     cleanup();
  63. }
  64. // 用于通知另一个进程数据已写入
  65. void SharedMemory::signal() {
  66.     if (hEvent_ != NULL) {
  67.         SetEvent(hEvent_);
  68.         ResetEvent(hEvent_);  // 重置事件
  69.     }
  70. }
  71. // 用于等待另一个进程写入数据
  72. void SharedMemory::wait() {
  73.     if (hEvent_ != NULL) {
  74.         WaitForSingleObject(hEvent_, INFINITE);
  75.     }
  76. }
  77. void SharedMemory::cleanup() {
  78.     if (lpBase_ != NULL) {
  79.         UnmapViewOfFile(lpBase_);
  80.         lpBase_ = NULL;
  81.     }
  82.     if (hMapFile_ != NULL) {
  83.         CloseHandle(hMapFile_);
  84.         hMapFile_ = NULL;
  85.     }
  86.     if (hFile_ != NULL) {
  87.         CloseHandle(hFile_);
  88.         hFile_ = NULL;
  89.     }
  90.     if (hEvent_ != NULL) {
  91.         CloseHandle(hEvent_);
  92.         hEvent_ = NULL;
  93.     }
  94.     if (hMutex_ != NULL) {
  95.         CloseHandle(hMutex_);
  96.         hMutex_ = NULL;
  97.     }
  98. }
  99. void SharedMemory::checkAndThrow(bool condition, const std::wstring& errorMessage) {
  100.     if (!condition) {
  101.         DWORD errorCode = GetLastError();
  102.         throw std::runtime_error(std::string(errorMessage.begin(), errorMessage.end()) + " Error code: " + std::to_string(errorCode));
  103.     }
  104. }
复制代码


        如许改进优化,代码似乎安全了些。。。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小秦哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表