前言:我们知道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; }
五、结果如下