团灭Windows进程通信(七)——主导地位文件映射

文章来源:http://blog.csdn.net/huanglong8/article/details/53954601

Windows提供了3种进行内存管理的方法:

  • 虚拟内存,最适合用来管理大型对象或结构数组。
  • 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据。
  • 内存堆栈,最适合用来管理大量的小对象。

跨进程共享数据的一种方式就是使用内存文件映射。
我的理解是,在内存中申请一片内存区域,这片内存就像将硬盘上的文件预先加载进去一样,这样各个进程间访问的时候,访问的就是同一片区域了,从而达到内存共享的目的。

文件映射原理-来源百度百科

WINAPI在这里给我们提供了同共享内存类似的函数,仅仅只有创建销毁这一部分会有不同。

创建文件映射内核对象

HANDLE WINAPI CreateFileMapping(
_In_HANDLE hFile,
_In_opt_LPSECURITY_ATTRIBUTES lpAttributes,
_In_DWORD flProtect,
_In_DWORD dwMaximumSizeHigh,
_In_DWORD dwMaximumSizeLow,
_In_opt_LPCTSTR lpName);

hFile:Long,指定欲在其中创建映射的一个文件句柄。0xFFFFFFFF(-1,即INVALID_HANDLE_VALUE)表示在页面文件中创建一个可共享的文件映射。这个参数通常被文件系统默认的可创建文件大小来限定,根据系统的不同,创建的内存文件大小的限值也不同。
lpFileMappigAttributes:SECURITY_ATTRIBUTES,它指明返回的句柄是否可以被子进程所继承,指定一个安全对象,在创建文件映射时使用。如果为NULL(用ByVal As Long传递零),表示使用默认安全对象。其中里面包含了安全描述符。

包含和被保护对象相关联的安全信息的数据结构。安全描述符包括谁拥有对象,以何种方式访问以及何种审查访问类型等信息。

flProtect:Long,下述常数之一:
PAGE_READONLY 以只读方式打开映射
PAGE_READWRITE 以可读、可写方式打开映射
PAGE_WRITECOPY 为写操作留下备份
可组合使用下述一个或多个常数:
SEC_COMMIT 为文件映射一个小节中的所有页分配内存
SEC_IMAGE 文件是个可执行文件
SEC_RESERVE 为没有分配实际内存的一个小节保留虚拟内存空间

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

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

lpName:String,指定文件映射对象的名字。如存在这个名字的一个映射,函数就会打开它。用vbNullString可以创建一个无名的文件映射。
调用CreateFileMapping的时候可能会出现的GetLastError的相应错误:
ERROR_FILE_INVALID 如果企图创建一个零长度的文件映射
ERROR_INVALID_HANDLE 内存空间的命名和现有的内存映射,互斥量,信号量,临界区有同名
ERROR_ALREADY_EXISTS 表示内存空间命名已经存在
在调用CreateFileMapping()时,可以用GetLastError()来检查其返回的错误信息。如果返回值为ERROR_ALREADY_EXISTS,则表示内存映射对象指定名字已经存在。有关其他返回值的意义见MSDN的详细说明。

映射内存创建好后需要调用WINAPI进行打开,并且如果有其他程序创建了映射,则直接用 OpenFileMapping 函数进行打开,从而实现两个进程间的通信。

HANDLE
OpenFileMappingA(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL bInheritHandle,
    _In_ LPCSTR lpName
    );

参数的意义同CreateFileMapping一样。

创建了内存文件后,则是很简单的WriteFile和ReadFile函数对文件内容进行读写操作。其中需要注意的是,MapViewOfFile 我们需要通过这个API函数来获取char* 类型的buff。

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 指定映射文件的字节数.
以上的参数较多,但如果没有特定需求的话,都可以指定默认值。

我们开始完成 团灭笔记 的示例。
首先写一个打开文件映射的函数,当没有时则创建再打开,当存在时则直接打开。

A进程源代码

#include <windows.h>
#include <stdio.h>

#define SENDMMFShare "SENDMMFShare"
#define RECVMMFShare "RECVMMFShare"

HANDLE hSendThread,hRecvThread;
LPDWORD hSendThreadID,hRecvThreadID;

HANDLE OpenOrCreateFileMapping(DWORD maxsize,LPCSTR lpname )
{
    HANDLE fileMap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,FALSE, lpname);
    if (!fileMap) 
    {
        fileMap = CreateFileMapping(INVALID_HANDLE_VALUE,NULL, PAGE_READWRITE, 0, maxsize,lpname);
    }
    return fileMap;
}

DWORD WINAPI Send(LPVOID lpParameter )
{
    char buff[0xFFF];
    ZeroMemory(buff,sizeof(buff));
    HANDLE s_hFileMap = NULL;
    char* pBuff = NULL;
    s_hFileMap = OpenOrCreateFileMapping(1024,SENDMMFShare);
    if(!s_hFileMap) 
    {
        printf("Can't create file mapping.\n");
        return 0;
    }
    if(GetLastError() == ERROR_ALREADY_EXISTS) 
    {
        printf("Mapping already exists - not created.\n");
        CloseHandle(s_hFileMap);
        return 0;
    }
    pBuff = (char*)MapViewOfFile(s_hFileMap,FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0xFFF);
    if(!pBuff)
    {
        printf("Can't map view of file.");
        CloseHandle(s_hFileMap);
        return 0;
    }
    while(true)
    {
        gets_s(buff,sizeof(buff));
        strncpy(pBuff,buff,0xFFF);
    }
    CloseHandle(s_hFileMap);
    UnmapViewOfFile(pBuff);
    return 0;
}

DWORD WINAPI Recv(LPVOID lpParameter )
{
    char buffer[2048] = {0};
    HANDLE hFileMapT = OpenOrCreateFileMapping(1024,RECVMMFShare);
    if (!hFileMapT) 
    {
        printf("Can't open mapping.");
        return 0;
    }
    char* pBuff = (char*)MapViewOfFile(hFileMapT, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
    if (!pBuff) 
    {
        printf("Can't map view.");
        CloseHandle(hFileMapT);
        return 0;
    }
    while(1)
    {
        if(strlen(pBuff)>0) 
        {
            printf("From B data: %s\n",pBuff);
            ZeroMemory(pBuff,1024);
        }
        Sleep(200);
    }
    UnmapViewOfFile(pBuff);
    CloseHandle(hFileMapT);
}

int main(int argc, char *argv[])
{
    hSendThread = CreateThread(NULL,0,Send,NULL,NULL,hSendThreadID);
    hRecvThread = CreateThread(NULL,0,Recv,NULL,NULL,hRecvThreadID);
    if( WaitForSingleObject(hSendThread,INFINITE))
        CloseHandle(hSendThread);
    if( WaitForSingleObject(hRecvThread,INFINITE))
        CloseHandle(hRecvThread);

    return 0;
}

B进程源代码

#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define SENDMMFShare "RECVMMFShare"
#define RECVMMFShare "SENDMMFShare"

HANDLE hSendThread,hRecvThread;
LPDWORD hSendThreadID,hRecvThreadID;

HANDLE OpenOrCreateFileMapping(DWORD maxsize,LPCSTR lpname )
{
    HANDLE fileMap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,FALSE, lpname);
    if (!fileMap) 
    {
        fileMap = CreateFileMapping(INVALID_HANDLE_VALUE,NULL, PAGE_READWRITE, 0, maxsize,lpname);
    }
    return fileMap;
}

DWORD WINAPI Send(LPVOID lpParameter )
{
    char buff[0xFFF];
    ZeroMemory(buff,sizeof(buff));
    HANDLE s_hFileMap = NULL;
    char* pBuff = NULL;
    s_hFileMap = OpenOrCreateFileMapping(1024,SENDMMFShare);
    if(!s_hFileMap) 
    {
        printf("Can't create file mapping.\n");
        return 0;
    }
    if(GetLastError() == ERROR_ALREADY_EXISTS) 
    {
        printf("Mapping already exists - not created.\n");
        CloseHandle(s_hFileMap);
        return 0;
    }
    pBuff = (char*)MapViewOfFile(s_hFileMap,FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0xFFF);
    if(!pBuff)
    {
        printf("Can't map view of file.");
        CloseHandle(s_hFileMap);
        return 0;
    }
    while(true)
    {
        gets_s(buff,sizeof(buff));
        strncpy(pBuff,buff,0xFFF);
    }
    CloseHandle(s_hFileMap);
    UnmapViewOfFile(pBuff);
    return 0;
}

DWORD WINAPI Recv(LPVOID lpParameter )
{
    char buffer[2048] = {0};
    HANDLE hFileMapT = OpenOrCreateFileMapping(1024,RECVMMFShare);
    if (!hFileMapT) 
    {
        printf("Can't open mapping.");
        return 0;
    }
    char* pBuff = (char*)MapViewOfFile(hFileMapT, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
    if (!pBuff) 
    {
        printf("Can't map view.");
        CloseHandle(hFileMapT);
        return 0;
    }
    while(1)
    {
        if(strlen(pBuff)>0) 
        {
            printf("From A data: %s\n",pBuff);
            ZeroMemory(pBuff,1024);
        }
        Sleep(200);
    }
    UnmapViewOfFile(pBuff);
    CloseHandle(hFileMapT);
}

int main(int argc, char *argv[])
{
    hSendThread = CreateThread(NULL,0,Send,NULL,NULL,hSendThreadID);
    hRecvThread = CreateThread(NULL,0,Recv,NULL,NULL,hRecvThreadID);
    if( WaitForSingleObject(hSendThread,INFINITE))
        CloseHandle(hSendThread);
    if( WaitForSingleObject(hRecvThread,INFINITE))
        CloseHandle(hRecvThread);

    return 0;
}

这里写图片描述

Windows进程通信_文件内存映射 下载

参考:
http://www.cnblogs.com/fangyukuan/archive/2010/09/09/1822216.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值