MemoryMappedFile 在 Mono in Linux 的开发笔记
前言
MemoryMappedFile(简称MMF)类是.NET中对内存映射文件进行操作的类,内存映射文件是非常高效的本地IO方案,由操作系统提供内存与IO文件之间的映射转换,对内存映射文件的更改由操作系统自动与物理文件进行高效的数据交换。在大文件处理中一般都需要使用到它,同时它也被用来做高效的进程间通讯的底层技术。
正因为它是如此的高效和便捷,所以在服务器程序开发中被广泛使用到。譬如,我们实现的基于Socket网络通讯程序中,在发送大数据时,需要对数据进行拆包组包的操作,这就往往需要对未接收完全的数据包进行缓存,在这个的场景中最好是使用MMF手动来对通讯包数据的缓存管理,倘若直接把这些数据放在.NET内置的集合、列表或字典中,那很可能会把.NET托管内存撑爆的。
当我把基于Socket的通讯类库代码运行在Mono on Linux中的时候,发现其使用到的MMF代码运行时异常了,本文就是对这一问题的处理过程的记录。
问题说明
Mono on Linux
我的代码是通过指定文件路径的方式创建MMF的,譬如文件路径为:/tmp/Zongsoft.Communication.Net#1.cache,在Windows中运行的很正常,但是在Mono on Linux中发生运行时异常:
Unhandled Exception:
System.IO.FileNotFoundException: 没有那个文件或目录 ---> Mono.Unix.UnixIOException: 没有那个文件或目录 [ENOENT].
at Mono.Unix.UnixMarshal.ThrowExceptionForLastError () [0x00000] in :0
at System.IO.MemoryMappedFiles.MemoryMapImpl.Open (System.String path, FileMode mode, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0
at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.String path, FileMode mode, System.String mapName, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0
难道在Mono中,需要先创建MMF对应的物理文件?好吧,那我就手动在临时文件夹下创建一个指定名称的空文件后,再来跑一遍,结果报了这个:
Unhandled Exception:
System.ArgumentException: capacity
at System.IO.MemoryMappedFiles.MemoryMapImpl.Open (System.String path, FileMode mode, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0
at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.String path, FileMode mode, System.String mapName, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0
难道是Mono对通过文件路径来创建MMF支持不力?好吧,那就试试通过文件流的方式来创建MMF吧,结果还是不行:
Unhandled Exception:
System.ArgumentException: capacity
at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.IO.FileStream fileStream, System.String mapName, Int64 capacity, MemoryMappedFileAccess access, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability, Boolean leaveOpen) [0x00000] in :0
看来,应该是跟capacity与物理文件的大小不匹配所致,好吧,那就在创建完文件流后,再使用文件流的SetLength来指定一个长度后,再通过该特定长度的文件流来创建MMF吧,结果果然创建成功!这说明在Mono中的创建MMF时,传入的目标文件必须是已经存在,且该文件长度不能为零。
由于刚才那个文件流的长度正好与创建MMF时capacity参数值相同,那么接下来我再来测试下,当文件流的长度与创建MMF时指定的capacity数值不同时,分别会发生什么情况。
1、文件流的长度大于创建MMF时capacity,成功,并且MMF创建后不会改变对应文件流的大小;
2、文件流的长度小于创建MMF时capacity:
Unhandled Exception:
System.ArgumentException: capacity
at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.IO.FileStream fileStream, System.String mapName, Int64 capacity, MemoryMappedFileAccess access, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability, Boolean leaveOpen) [0x00000] in :0
.NET on Windows
再简单说明下MemoryMappedFile类在.NET Windows平台中的创建行为:
- 通过文件路径的方式,如果对应的文件不存在则自动创建一个对应指定capacity大小的文件。
- 通过文件流的方式,如果对应文件流的大小小于capacity则成功;如果对应文件流大小大于capacity则失败,提示指定的文件流大小太小。
Mono 源码简查
通过查看Mono-3.0.12的源码,发现MMF类的如下代码:
public static MemoryMappedFile CreateNew(string mapName, long capacity, MemoryMappedFileAccess access,
MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
HandleInheritability inheritability)
{
return CreateFromFile(mapName, FileMode.CreateNew, mapName, capacity, access);
}public static MemoryMappedFile CreateOrOpen(string mapName, long capacity, MemoryMappedFileAccess access)
{
return CreateFromFile(mapName, FileMode.OpenOrCreate, mapName, capacity, access);
}
可见它们是都是通过CreateFromFile方法来处理的,并且将mapName作为文件路径来使用,所以,调用这两个方法要留心了,因为它与.NET(Windows)平台的实现是完全不同的,除此以外的其他创建或打开方法未实现,请勿使用!代码如下:
public static MemoryMappedFile OpenExisting(string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
{
throw new NotImplementedException();
}
总结
综上所述,为了让代码能够在Linux和Windows平台都正常运行,建议统一使用
MemoryMappedFile.CreateFromFile(
FileStream fileStream,
String mapName,
Int64 capacity,
MemoryMappedFileAccess access,
System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity,
HandleInheritability inheritability,
Boolean leaveOpen)
方法来创建MMF,并且在调用前确保指定的文件流大小与capacity参数值相同。
MemoryMappedFile 在 Mono in Linux 的开发笔记的更多相关文章
- 嵌入式linux驱动开发 笔记
@ 目录 首个驱动hellodrv 1.编写源码 2.编译模块 3.加载驱动 首个驱动hellodrv 3.如果下载不到,就自己编写,并编译驱动. 1.编写源码 2.编译模块 1.先写makefile ...
- 驱动开发学习笔记. 0.06 嵌入式linux视频开发之预备知识
驱动开发读书笔记. 0.06 嵌入式linux视频开发之预备知识 由于毕业设计选择了嵌入式linux视频开发相关的项目,于是找了相关的资料,下面是一下预备知识 UVC : UVC,全称为:USB v ...
- Linux及Arm-Linux程序开发笔记(零基础入门篇)
Linux及Arm-Linux程序开发笔记(零基础入门篇) 作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/bee ...
- 【Linux开发】Linux及Arm-Linux程序开发笔记(零基础入门篇)
Linux及Arm-Linux程序开发笔记(零基础入门篇) 作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/beer ...
- 嵌入式linux应用开发完全手册学习笔记一
2015.3.25星期三 晴 有两个星期没写学习日记了,找个时间把这段时间做的电子词典和ARM小项目总结一下. 下面的知识点总结,U-BOOT:参考PDF文档:嵌入式linux应用开发完全手册 当虚拟 ...
- Linux实战教学笔记08:Linux 文件的属性(上半部分)
第八节 Linux 文件的属性(上半部分) 标签(空格分隔):Linux实战教学笔记 第1章 Linux中的文件 1.1 文件属性概述(ls -lhi) linux里一切皆文件 Linux系统中的文件 ...
- Linux实战教学笔记03:操作系统发展历程及系统版本选择
标签(空格分隔): Linux实战教学笔记-陈思齐 第1章 Linux简介 1.1 什么是操作系统? 简单讲:操作系统就是一个人与计算机硬件的中介. 操作系统,英文名称Operating System ...
- Linux实战教学笔记02:计算机系统硬件核心知识
标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 互联网企业常见服务器介绍 1.1 互联网公司服务器品牌 - DELL(大多数公司,常用) - HP - IBM(百度在用) 浪潮 联想 航天联 ...
- storysnail的Linux串口编程笔记
storysnail的Linux串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据Ge ...
随机推荐
- 关于CryptoJS中md5加密以及aes加密的随笔
最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...
- git-简单流程(学习笔记)
这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...
- Castle Core 4.0.0 alpha001发布
时隔一年多以后Castle 项目又开始活跃,最近刚发布了Castle Core 4.0.0 的alpha版本, https://github.com/castleproject/Core/releas ...
- POCO Controller 你这么厉害,ASP.NET vNext 知道吗?
写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...
- javascript动画系列第四篇——拖拽改变元素大小
× 目录 [1]原理简介 [2]范围圈定 [3]大小改变[4]代码优化 前面的话 拖拽可以让元素移动,也可以改变元素大小.本文将详细介绍拖拽改变元素大小的效果实现 原理简介 拖拽让元素移动,是改变定位 ...
- Spring aop应用之实现数据库读写分离
Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...
- QQ空间动态爬虫
作者:虚静 链接:https://zhuanlan.zhihu.com/p/24656161 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 先说明几件事: 题目的意 ...
- MediatorPattern(中介者模式)
/** * 中介者模式 * @author TMAC-J * 研究了这么多设计模式,觉得无非就是几点: * 1.若两个类有耦合关系,设立一个中间类,处理两个类的关系,把两个类的耦合降低 * 2.面向接 ...
- 微信小程序开发日记——高仿知乎日报(上)
本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP 要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该 ...
- BPM配置故事之案例14-数据字典与数据联动
小明遇到了点麻烦,他昨天又收到了行政主管发来的邮件,要求把出差申请单改由H3 BPM进行,表单如下 行政主管的出差申请表 小明对表单进行了调整,设计出了一份适合在系统中使用的表单,但在"出差 ...