Windows进程通讯 -- 共享内存

享内存的方式原理就是将一份物理内存映射到不一样进程各自的虚拟地址空间上,这样每一个进程均可以读取同一份数据,从而实现进程通讯。由于是经过内存操做实现通讯,所以是一种最高效的数据交换方法。安全

共享内存在 Windows 中是用 FileMapping 实现的,从具体的实现方法上看主要经过如下几步来实现:app

一、调用 CreateFileMapping 建立一个内存文件映射对象;函数

复制代码
HANDLE CreateFileMapping(
  HANDLE hFile,              // handle to file to map
  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
                             // optional security attributes
  DWORD flProtect,           // protection for mapping object
  DWORD dwMaximumSizeHigh,   // high-order 32 bits of object size
  DWORD dwMaximumSizeLow,    // low-order 32 bits of object size
  LPCTSTR lpName             // name of file-mapping object
);
复制代码

经过这个API函数 将建立一个内存映射文件的内核对象,用于映射文件到内存。与虚拟内存同样,内存映射文件能够用来保留一个地址空间的区域,并将物理存储器提交
给该区域。它们之间的差异是,物理存储器来自一个已经位于磁盘上的文件,而不是系统的页文件。spa

复制代码
hFile:用于标识你想要映射到进程地址空间中的文件句柄。该句柄能够经过调用C r e a t e F i l e函数返回。这里,咱们并不须要一个实际的文件,因此,就不须要调用 CreateFile 建立一个文件, hFile 这个参数能够填写 INVALID_HANDLE_VALUE; 

lpFileMappingAttributes:参数是指向文件映射内核对象的 SECURITY_ATTRIBUTES结构的指针,一般传递的值是 N U L L;

flProtect:对内存映射文件的安全设置(PAGE_READONLY 以只读方式打开映射;PAGE_READWRITE 以可读、可写方式打开映射;PAGE_WRITECOPY 为写操做留下备份)

dwMaximumSizeHigh:文件映射的最大长度的高32位。

dwMaximumSizeLow:文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。

lpName:指定文件映射对象的名字,别的进程就能够用这个名字去调用 OpenFileMapping 来打开这个 FileMapping 对象。
 
若是建立成功,返回建立的内存映射文件的句柄,若是已经存在,则也返回其句柄,可是调用 GetLastError()返回的错误码是:183(ERROR_ALREADY_EXISTS),若是建立失败,则返回NULL;
复制代码

二、调用 MapViewOfFile 映射到当前进程的虚拟地址上;指针

若是调用CreateFileMapping成功,则调用MapViewOfFile函数,将内存映射文件映射到进程的虚拟地址中;code

复制代码
LPVOID MapViewOfFile(
  HANDLE hFileMappingObject,  // file-mapping object to map into 
                              // address space
  DWORD dwDesiredAccess,      // access mode
  DWORD dwFileOffsetHigh,     // high-order 32 bits of file offset
  DWORD dwFileOffsetLow,      // low-order 32 bits of file offset
  DWORD dwNumberOfBytesToMap  // number of bytes to map
);
 
hFileMappingObject:CreateFileMapping()返回的文件映像对象句柄。
dwDesiredAccess: 映射对象的文件数据的访问方式,并且一样要与CreateFileMapping()函数所设置的保护属性相匹配。
dwFileOffsetHigh: 表示文件映射起始偏移的高32位.
dwFileOffsetLow: 表示文件映射起始偏移的低32位.
dwNumberOfBytesToMap :文件中要映射的字节数。为0表示映射整个文件映射对象。
复制代码

三、在接收进程中打开对应的内存映射对象对象

在数据接收进程中,首先调用OpenFileMapping()函数打开一个命名的文件映射内核对象,获得相应的文件映射内核对象句柄hFileMapping;若是打开成功,则调用MapViewOfFile()函数映射对象的一个视图,将文件映射内核对象hFileMapping映射到当前应用程序的进程地址,进行读取操做。(固然,这里若是用CreateFileMapping也是能够获取对应的句柄)blog

复制代码
HANDLE OpenFileMapping(
  DWORD dwDesiredAccess,  // access mode
  BOOL bInheritHandle,    // inherit flag
  LPCTSTR lpName          // pointer to name of file-mapping object
);
 
dwDesiredAccess:同MapViewOfFile函数的dwDesiredAccess参数
bInheritHandle :如这个函数返回的句柄能由当前进程启动的新进程继承,则这个参数为TRUE。
lpName :指定要打开的文件映射对象名称。
复制代码

四、进行内存映射文件的读写继承

一旦MapViewOfFile调用成功,就能够像读写本进程地址空间的内存区同样,进行内存的读写操做了。进程

复制代码
//读操做:

// 打开成功,映射对象的一个视图,获得指向共享内存的指针,显示出里面的数据
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pBuffer)
{
cout << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
//cout << "读取共享内存数据:" << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
}
else
{
cout << "打开共享数据失败!" << endl;
}

 

//写操做:

// 映射对象的一个视图,获得指向共享内存的指针,设置里面的数据
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pBuffer)
{
memcpy((CThostFtdcDepthMarketDataField*)pBuffer, DepthMarketData, sizeof(CThostFtdcDepthMarketDataField));
//cout << "写入共享内存数据:" << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
}
else
{
cout << "打开共享数据失败!" << endl;
}

复制代码

五、清理内核对象

在用完后,要取消本进程地址空间的映射,并释放内存映射对象。

    //取消本进程地址空间的映射;   
    UnmapViewOfFile(pLocalMem);  
      
    pLocalMem=NULL;   
    //关闭文件映射内核文件  
    CloseHandle(hFileMapping);
相关文章
相关标签/搜索