ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

C++通过共享内存实现进程间通信(windows平台)

2020-09-12 15:03:50  阅读:439  来源: 互联网

标签:文件 映射 MAP windows C++ PAGE 间通信 FILE CreateFileMapping


前言:我们知道windows os上有很多的api,编程语言对os进行操作,无论什么语言,最终都是通过windows api 的。

在windows编程中,有个概念是句柄,句柄指向资源(一切可以利用的物理的逻辑的资源),其中文件操作,可以将文件映射到内存,此处的文件是广义的文件,可以指内存对象,邮件槽等。

在windows中创建一个指向文件的虚拟内存,然后多个进程创建各个进程对这块内存的映射,通过访问各个进程的映射内存对这块虚拟内存进行访问,是共享内存实现的原理。

下图很好的标明了整个原理。

 

 一、相关的API函数

内存映射API函数CreateFileMapping创建一个有名的共享内存:

HANDLE CreateFileMapping(
HANDLE hFile,                         // 映射文件的句柄,设为0xFFFFFFFF以创建一个进程间共享的对象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,   // 安全属性
DWORD flProtect,                                                                   // 保护方式
DWORD dwMaximumSizeHigh,                                           //对象的大小 
DWORD dwMaximumSizeLow, 
LPCTSTR lpName                                                                 // 必须为映射文件命名
);

HANDLE CreateFileMapping(
HANDLE hFile, //物理文件句柄
LPSECURITY_ATTRIBUTES lpAttributes, //安全设置
DWORD flProtect, //保护设置
DWORD dwMaximumSizeHigh, //高位文件大小
DWORD dwMaximumSizeLow, //低位文件大小
LPCTSTR lpName //共享内存名称
);
hFile 指定欲在其中创建映射的一个文件句柄。INVALID_HANDLE_VALUE,即0xFFFFFFFF表示在页面文件中创建一个可共享映射文件。
lpAttributes 它指明返回的句柄是否可以被子进程所继承,指定一个安全对象,在创建文件映射时使用。如果为NULL(用ByVal As Long传递零),表示使用默认安全对象
flProtect 有以下几种方式:
PAGE_READONLY 以只读方式打开映射
PAGE_READWRITE 以可读、可写方式打开映射
PAGE_WRITECOPY 为写操作留下备份也可组合使用下述一个或多个常数:
SEC_COMMIT 为文件映射一个小节中的所有页分配内存
SEC_IMAGE 文件是个可执行文件
SEC_RESERVE 为没有分配实际内存的一个小节保留虚拟内存空间
dwMaximumSizeHigh 文件映射的最大长度的高32位
dwMaximumSizeLow 文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。
lpName 指定文件映射对象的名字。如存在这个名字的一个映射,函数就会打开它。用vbNullString可以创建一个无名的文件映射。

 

LPVOID WINAPI MapViewOfFile( //将一个文件映射对象映射到当前应用程序的地址空间。
  __in HANDLE hFileMappingObject,
  __in DWORD dwDesiredAccess,
  __in DWORD dwFileOffsetHigh,
  __in DWORD dwFileOffsetLow,
  __in SIZE_T dwNumberOfBytesToMap
  );
hFileMappingObject 为CreateFileMapping返回的文件映像对象句柄。
dwDesiredAccess 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。
可取以下值:
FILE_MAP_ALL_ACCESS 等价于CreateFileMapping的 FILE_MAP_WRITE|FILE_MAP_READ.文件映射对象被创建时必须指定PAGE_READWRITE 选项.
FILE_MAP_COPY 可以读取和写入文件.写入操作会导致系统为该页面创建一份副本.在调用 CreateFileMapping时 必须 传入PAGE_WRITECOPY保护属性.
FILE_MAP_EXECUTE 可以将文件中的数据在调用CreateFileMapping时可以传入PAGE_EXECUTE_READWRITE或PAGE_EXECUTE_READ保护属性.
FILE_MAP_READ 可以读取文件.在调用CreateFileMapping时可以传入PAGE_READONLY或PAGE_READWRITE保护属性.
FILE_MAP_WRITE 可以读取和写入文件.在调用CreateFileMapping时必须传入PAGE_READWRITE保护属性.
dwFileOffsetHigh 表示文件映射起始偏移的高32位.
dwFileOffsetLow 表示文件映射起始偏移的低32位.(64KB对齐不是必须的)
dwNumberOfBytes 指定映射文件的字节数.

三、写端的实现

#include <iostream>
#include <windows.h>
#include <string.h>
#include <cstring>
#include <istream>
using namespace std;

int main()
{
    unsigned long buff_size = 1024 * 5;

    PVOID pBuff=NULL;

    HANDLE hFile = CreateFile(L"shared_memory",    //如果不映射到物理磁盘上,可以不用创建
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (hFile==INVALID_HANDLE_VALUE)
    {
        cout << "create file error." << endl;
    }

    HANDLE hFile_mapping = CreateFileMapping(
        INVALID_HANDLE_VALUE,                  // 如果需要创建,而不是内存对象,可以传入hFile
        NULL,
        PAGE_READWRITE,
        0,
        buff_size,
        L"shared_memory");

    if (NULL != hFile_mapping)
    pBuff = MapViewOfFile(
        hFile_mapping,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        buff_size
    );

    char str[1024];

    while (true)
    {
        cout << "please enter data .\"exit\" end app" << endl;
        cin.getline(str,1024);
        if (str!="exit")
        {
            if (NULL != pBuff)
                memcpy(pBuff, str, 1024);
        }
        else if (str == "exit")
        {
            break;
        }

    }

    if (NULL != pBuff)
        FlushViewOfFile(pBuff, buff_size);

    cout << "finish write, wait ..." << endl;
    Sleep(20000);

    if (NULL!=pBuff)
        UnmapViewOfFile(pBuff);

    if (NULL != hFile_mapping)
        CloseHandle(hFile_mapping);

    if (NULL != hFile)
        CloseHandle(hFile);

}

四、读端的实现

#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
    const unsigned long buff_size = 1024*5;
    LPVOID pBuff = NULL;

    HANDLE handle_file_mapping = OpenFileMapping(
        FILE_MAP_ALL_ACCESS,
        NULL,
        L"shared_memory");

    if (NULL!= handle_file_mapping)
        pBuff = MapViewOfFile(
            handle_file_mapping,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        0);

    if (handle_file_mapping==NULL|| pBuff==NULL)
    {
        cout << "create shared memory faild,please waitting the memory created and exect the app again!" << endl
             <<"enter any key to  exit the app!";
        string temp;
        cin >> temp;
        return 0;
    }

    string str;

    while (true)
    {
        cout << "enter \"yes\" receive data, or enter \"exit\" " << endl;
        cin >> str;
        if (str=="yes")
        {
            char* share_buffer = (char*)pBuff;
            cout << share_buffer << endl;
        }
        else if (str == "exit")
        {
            break;
        }

    }

    if (NULL!= pBuff)
        UnmapViewOfFile(pBuff);
    if (NULL != handle_file_mapping)
        CloseHandle(handle_file_mapping);
    return 0;
}

五、结果如下

 

标签:文件,映射,MAP,windows,C++,PAGE,间通信,FILE,CreateFileMapping
来源: https://www.cnblogs.com/xietianjiao/p/13657031.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有