`
izuoyan
  • 浏览: 8934203 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

.NET 4.0中使用内存映射文件实现进程通讯

阅读更多

.NET 4.0系列之

使用内存映射文件实现进程通讯

************************************************************************

版权声明:

此文章由原作者金旭亮出于技术共享与交流目的而发布,作者金旭亮拥有全部版权。任何人及机构不得将其用于商业用途,如收费培训及出版技术书籍,有这方面需求的个人及培训机构请与本人直接联系,本人可提供针对.NET 3.54.0完备的教学与培训资料。

本人联系方式:

JinXuLiang@bit.edu.cn 北京理工大学计算机学院软件研究所 100081

更多技术与学习资源请关注作者博客:

http://blog.csdn.net/bitfan

金旭亮

2009.8.12

*************************************************************************

操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段。Win32 API中也包含有创建内存映射文件的函数,然而,这些函数都运行于非托管环境下,在.NET中只能通过平台调用机制来使用它们,用起来很不方便。幸运的是,.NET 4.0新增加了一个System.IO. MemoryMappedFiles命名空间,其中添加了几个类和相应的枚举类型,从而使我们可以很方便地创建内存映射文件。

1 内存映射文件原理

所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特定的文件相对应。进程将这块内存区域映射到自己的地址空间中,访问它就象是访问普通的内存一样。

1 内存映射文件原理图

.NET中,使用MemoryMappedFile对象表示一个内存映射文件,通过它的CreateFromFile()方法根据磁盘现有文件创建内存映射文件,调用这一方法需要提供一个与磁盘现有文件相对应的FileStream对象。

以下示例代码动态创建一个MyFile.dat文件,然后将其映射到系统内存中,设定容量为1M

FileStream fs = new FileStream("MyFile.dat", FileMode.Create,

FileAccess.ReadWrite);

MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile(fs, "MyFile", 1024*1024);

注意用于创建内存映射文件的文件流必须是可读写的

扩充阅读:

于内存映射文件的容量

默认情况下,在调用MemoryMappedFile.CreateFromFile()方法时如果不指定文件容量,那么,创建的内存映射文件的容量等同于文件的大小。

在上面的示例代码中,由于磁盘文件是临时生成的,其长度为0,所以,必须在创建内存映射文件时同时指定其容量。

在设定内存映射文件的容量时,其值不能小于磁盘文件的现有长度,但可以比它大。但要注意这将导致一个戏剧化的结果:磁盘文件自动增长到声明的容量大小!

可以多次调用MemoryMappedFile.CreateFromFile(),每次传给它一个更大的容量数值以不断扩充磁盘文件的大小。

当不再使用一个MemoryMappedFile对象时,注意应该及时地调用其Dispose()方法释放它所占有的系统资源。因为MemoryMappedFile实际上对应着运行操作系统核心的核心对象,如果不及时关闭,会造成操作系统核心资源(比如句柄)的浪费,要等到MemoryMappedFile对象被CLR垃圾回收,或者整个进程中止时,这些资源才会被操作系统回收再利用。

另外,内存映射文件的容量其实是指最大允许分配给内存映射文件的内存存储区字节数,并不意味着系统会马上分配指定容量的内存。进程中访问这块映射到磁盘文件中的存储区时,操作系统如果发现其内容还未装入内存,就会从磁盘文件中装入相应内容到内存中。因此,不用担心声明一个大的内存映射文件容量会导致内存的浪费。

MemoryMappedFile对象创建之后,我们并不能直接对其进行读写,必须通过一个MemoryMappedViewAccessor对象来访问这个内存映射文件。

MemoryMappedFile. CreateViewAccessor()方法可以创建MemoryMappedViewAccessor对象,而此对象提供了一系列读写的方法,用于向内存映射文件中读取和写入数据。

以下示例代码创建了一个内存映射文件访问对象并使用它写入数据:

FileStream fs =…; //创建FileStream对象

MemoryMappedFile memoryFile=…; //创建内存映射文件

//创建内存映射文件访问对象

MemoryMappedViewAccessor accessor=

memoryFile.CreateViewAccessor(0, 1024);

for (int i = 0; i < 1024; i+=2)

accessor.Write(i, ‘c’);

上述代码中要注意,在创建内存映射文件访问对象需要指定它所能访问的内存映射文件的内容范围,这个“范围”称为“内存映射视图(Memory Mapped View)”。可以将它与“放大镜”类比,当使用一个放大镜阅读书籍时,一次只能放大指定部分的文字。类似地,我们只能在内存映射视图所规定的范围内存取内存映射文件。

在上述代码中,我们看到内存映射视图对象accessor只提取了内存映射文件开头1024个字节的内容,然后,向其中写入了512个“c”字符。

当调用内存映射视图对象的Write()方法时,需要指明从哪个位置(即方法的第一个参数)开始写入数据,并且需要计算清楚要写入的数据占几个字节,这样,当写入下一个数据时,就知道应该从哪个位置开始。

注意,Write()方法中的位置是相对视图对象而非内存映射文件本身,因此,此位置数值再加上视图距内存映射文件开头的位置数据才是写入的数据在文件中的真实位置。

Write()方法有多个重载形式,可以向内存映射文件中写入多种类型的数据,但要注意计算清楚其写入的位置,避免造成数据覆盖问题。

类似地,内存映射视图对象提供了多个重载的Read()方法,可以从内存映射文件中读取数据。

比较有趣的是,在同一个进程中可以针对同一个内存映射文件创建多个视图对象,从而允许我们同时修改同一个文件的不同部分,在关闭视图对象时由操作系统保证将所有修改都写回到原始文件中。

下面我们来看一个示例。

2 在同一进程内同时读写同一内存映射文件

示例项目UseMMFInProcess运行时会在程序的当前目录下创建一个“MyFile.dat”文件,然后,创建了两个内存映射视图对象,分别向文件的前半部分和后半部分写入不同的数据,然后再从中读出来( 2)。

2 示例项目UseMMFInProcess

这个示例展示的技术很基础,请读者自行查看源码。

3 使用内存映射文件在进程间传送值类型数据

在前面的例子中,内存映射文件直接与某个特定的磁盘文件相对应,事实上,我们也可以不用创建磁盘文件而直接使用Windows的分页文件。这种方式是实现进程间互传数据的典型方式。

调用MemoryMappedFile.CreateNew()MemoryMappedFile.CreateOrOpen()方法可以在系统内存(System Memory)中直接创建一个内存映射文件,这个内存映射文件所对应的“物理文件”是Windows的系统分页文件。两个方法都需要给映射文件指定一个唯一的名称。不同之处在于CreateOrOpen ()方法在指定名称的映射文件存在时就直接将其返回给进程,而CreateNew()方法始终是新创建一个内存映射文件。

扩充阅读:

Windows的系统分页文件和休眠文件

默认情况下,在安装Windows的分区根目录下,会找到两个具有“隐藏”属性的pagefile.syshiberfil.sys文件,前者(pagefile.sys)就是Windows的分页文件,用于保存从物理内存中换出的内存页,我们可以用它的一部分来创建内存映射文件。后者(hiberfil.sys)则是“系统休眠”文件,当Windows启用了休眠功能时,就会在硬盘上找到这个文件,它的内容是系统休眠时物理内存中的数据,当计算机从休眠中“醒”过来时,通过从此文件中加载信息以恢复上次工作的状态。

内存映射文件创建好以后,可以如同前面介绍的方法一样创建视图对象,然后使用ReadWrite系列方法存取。

只要指定同一个名字,那么,多个进程就可以使用同一个内存映射文件交换数据。示例UseMMFBetweenProcess展示了在两个进程间相互交换一个结构体变量的情况:

3 示例项目UseMMFBetweenProcess

两个进程要交换的数据格式如下:

public struct MyStructure

{

public int IntValue

{ get; set; }

public float FloatValue

{ get; set; }

}

启动UseMMFBetweenProcess程序的两个实例,在其中一个窗体上输入两个数字之后,点击“保存”按钮,然后在另一个进程的窗体上点击“提取”,可以看到另一个进程写入的信息出现在本进程的文本框中。

示例程序采用MemoryMappedFile.CreateOrOpen()方法创建或打开一个内存映射文件,然后调用MemoryMappedViewAccessor类的泛型方法Write<T>()Read<T>()向内存映射文件中写入和读取数据。

注意,泛型方法Write<T>()Read<T>()中的泛型参数T必须是值类型(比如整型int和结构体struct),特别地,对于用户自定义的结构体,要求其成员也必须是值类型。

例如,以下结构体将无法写入到内存映射文件中,因为其成员Infostring类型的,这是一个引用类型。

public struct ErrorStruct

{

public string Info;

}

之所以要求泛型参数不能是引用类型,其道理非常简单,如果结构体中的某个成员是引用类型,那么在程序运行时,计算机无法知道应该向内存映射文件中写入多少个字节,因为引用类型的变量所引用的对象位于托管堆中,其占用存储空间的大小不经过计算是难以确定的,而完成这个计算工作将花费不少的系统资源(想想一个对象可能又会引用到另一个对象就明白了),这会严重影响内存映射文件读写操作效率。

两个进程不能交换引用类型的数据,这个限制似乎还不小,但事实上,我们完成可以通过对象序列化技术来突破这个限制,在两个进程间交换任意大小的对象(只要内存映射文件有足够的容量)。请看下一小节的示例UseMMFBetweenProcess2

4 利用序列化技术通过内存映射文件实现进程通讯

图4 示例:UseMMFBetweenProcess2

4所示,运行示例程序的多个实例,加载图片并输入图片说明,点击相应按钮后,可以在多个进程间直接交换以下格式的信息:

[Serializable]

class MyPic

{

public Image pic; //图片

public string picInfo; //图片信息说明

}

请注意这是一个引用类型的数据对象,并且它附加了可序列化“[Serializable]”的代码属性。

如果要向内存映射文件中序列化对象,必须将内存映射文件转换为可顺序读取的流。幸运的是,MemoryMappedFile类的CreateViewStream()方法可以创建一个MemoryMappedViewStream对象,通过它即可序列化对象,其代码框架如下:

//创建或打开内存映射文件

MemoryMappedFile memoryFile = MemoryMappedFile.CreateOrOpen(...);

//创建内存映射流

MemoryMappedViewStream stream = memoryFile.CreateViewStream();

//创建要在进程间交换的信息对象

MyPic obj =...;

//向内存映射流中序列化对象

IFormatter formatter = new BinaryFormatter();

stream.Seek(0, SeekOrigin.Begin);

formatter.Serialize(stream, obj);

请读者自行阅读源码了解更多技术细节。

=================================================

在CSDN下载频道下载本文示例源码及PDF文档

分享到:
评论

相关推荐

    .NET 4.0中使用内存映射文件实现进程间通讯

    重点展示如何使用.NET4.0中新增的MemoryMappedFile类实现进程间通讯,资源包中包含一个PDF文档,以及VS2010格式的三个示例文件。 与作者交流请访问 http://blog.csdn.net/bitfan/archive/2009/08/12/4438458.aspx 更...

    .NET4利用MemoryMappedFile实现跨进程多个可执行程序之间的通信

    对于需要传输图片等引用类数据,可以通过序列化和反序列化配合共享内存实现跨进程(跨EXE)通信 共享内存可以从磁盘文件中映射,也可以直接映射到内存中。 如果映射到磁盘中,可以实现持久化。 如果只映射到内存中,...

    SharedMemory:C#共享内存类,用于在进程之间共享数据(数组,缓冲区和循环缓冲区)

    该库在.NET 4.0+中使用.NET MemoryMappedFile类,并为.NET 3.5实现其自己的包装器类。班级SharedMemory.SharedBuffer一个抽象的基类,它包装了一个内存映射文件,公开了读/写操作,并实现了一个小的标头,以允许...

    aspnet web api 超实用案例

     4、模型绑定与验证: 模型绑定器可以轻易地从 HTTP 请求中提取数据并转换成在动作方法中使用的 .Net 对象;  5、过滤: Web API 支持过滤, 包括总所周知的 [Authorize] 过滤标记, 可以为 Action 添加并插入...

    Test.html 测试文件

    像ASP.NET一样,ASP.NET中承载的WCF服务可以利用ASP.NET共享宿主模型,在此模型中,多个应用程序驻留在一个公共辅助进程中以提高服务器密度和可伸缩性。 IIS中承载的WCF服务与ASP.NET2.0使用相同的动态编译模型,该...

    vc++ 应用源码包_1

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_2

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_6

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_5

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_3

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 开发实例源码包

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    JAVA上百实例源码以及开源项目

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    UNIX高级编程 计算机科学丛书

    所有实例的源代码文件都可经Internet用匿名ftp取到,其主机站点是ftjp.uu.net,文件名是published/books/stevens.advprog.tar.Z。在你的机器上可对这些源代码进行修改并运行它们。 用于测试实例的系统 不幸的是所有...

    JAVA上百实例源码以及开源项目源代码

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    IIS6.0 IIS,互联网信息服务

    四、在Vista系统中安装IIS7.0相对于早先的版本,IIS 7.0 带来了许多引人注目的新特色新功能,比如基于 Microsoft .NET Framework 的全局配置文件,可简单地通过文本编辑器或 Microsoft Visual Studio 编辑;...

    McAfee 8.0 简体中文

    使用此功能可以阻挡在共享文件夹中放置了含有已感染病毒文件的远程计 算机的进一步访问。您可以指定阻挡这些连接的时间长短。如果您希望在指 定的时间限制之前取消阻挡所有的连接,您可以在按访问扫描统计...

    Microsoft SQL Server 2005 Express Edition SP3

    如果已在安装过程中使用了默认的命名实例,则将实例指定为“SQLExpress”。 [顶部] 2.3 管理 SQL Server Express 的工具 有关连接到 SQL Server Express 数据库并进行管理的信息,请参阅 Microsoft 知识库文章 ...

    网管教程 从入门到精通软件篇.txt

    IV:Open Inventor中使用的文件格式 IVD:超过20/20微观数据维数或变量等级文件 IVP:超过20/20的用户子集配置文件 IVT:超过20/20表或集合数据文件 IVX:超过20/20微数据目录文件 IW:Idlewild屏幕保护程序 ...

Global site tag (gtag.js) - Google Analytics