怎样在.net平台合理安全的使用Named Shared Memory以在进程间共享数据 ...

打印 上一主题 下一主题

主题 995|帖子 995|积分 2985

传统的应用程序间跨进程高速的传输数据有多种方式,作为Win32下的主流,许多程序中都会看到CreateFileMapping函数,这让大家分享一下怎样合理而且安全的建立一个内查对象,以及整个情况的配景和作业流程。

        [StructLayout(LayoutKind.Sequential)]
        internal class SECURITY_ATTRIBUTES
        {
            public int nLength;
            public SafeLocalMemHandle lpSecurityDescriptor;
            public bool bInheritHandle;
            public SECURITY_ATTRIBUTES()
            {
                this.nLength = 12;
                this.lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false);
            }
        }

        [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
        internal sealed class SafeFileMappingHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
            internal SafeFileMappingHandle() : base(true) { }
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
            internal SafeFileMappingHandle(IntPtr handle, bool ownsHandle)
                : base(ownsHandle)
            {
                SetHandle(handle);
            }
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
            private static extern bool CloseHandle(IntPtr handle);
            protected override bool ReleaseHandle()
            {
                return CloseHandle(handle);
            }
        }

        [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
        internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            internal SafeLocalMemHandle() : base(true) { }
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
            internal SafeLocalMemHandle(IntPtr existingHandle, bool ownsHandle)
                : base(ownsHandle)
            {
                SetHandle(existingHandle);
            }
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor, int StringSDRevision, out SafeLocalMemHandle pSecurityDescriptor, IntPtr SecurityDescriptorSize);
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll")]
            private static extern IntPtr LocalFree(IntPtr hMem);
            protected override bool ReleaseHandle()
            {
                return (LocalFree(handle) == IntPtr.Zero);
            }
        }
        internal sealed class SafeViewOfFileHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
            internal SafeViewOfFileHandle() : base(true) { }
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
            internal SafeViewOfFileHandle(IntPtr handle, bool ownsHandle) : base(ownsHandle) { SetHandle(handle); }
            protected override bool ReleaseHandle()
            {
                if (UnmapViewOfFile(handle))
                {
                    base.handle = IntPtr.Zero;
                    return true;
                }
                return false;
            }
        }


        const int FILE_MAP_COPY = 0x0001;
        const int FILE_MAP_WRITE = 0x0002;
        const int FILE_MAP_READ = 0x0004;
        const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;

        const int PAGE_READONLY = 0x02;
        const int PAGE_READWRITE = 0x04;
        const int PAGE_WRITECOPY = 0x08;
        const int PAGE_EXECUTE = 0x10;
        const int PAGE_EXECUTE_READ = 0x20;
        const int PAGE_EXECUTE_READWRITE = 0x40;
        const int SEC_COMMIT = 0x8000000;
        const int SEC_IMAGE = 0x1000000;
        const int SEC_NOCACHE = 0x10000000;
        const int SEC_RESERVE = 0x4000000;

        const int INVALID_HANDLE_VALUE = -1;

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern SafeFileMappingHandle OpenFileMapping(int dwDesiredAccess, bool bInheritHandle, string lpName);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern SafeFileMappingHandle CreateFileMapping(IntPtr hFile, SECURITY_ATTRIBUTES lpFileMappingAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", ExactSpelling = true)]
        static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern SafeViewOfFileHandle MapViewOfFile(SafeFileMappingHandle handle, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumerOfBytesToMap);

安全的建立非托管平台的handle是整篇我推许的地方,由于内查对象如果以外的未能释放会产生内存泄漏,危害很严重。.net平台下PInvoke支持多种封送策略,以是尽量的使用安全的handle显得尤为重要。
下面简要讲一下情况,方法流程和序次参数。
情况:
文件映射的主体是文件,所有的映射会把文件流在当前建立视图的进程区建立一个地址映射,对这个内存地址的作业,就是对文件的作业,由于是在内存中建立了映射,以是每个进程可以独立的读写本身的映射区,最后可以调用方法同步革新到文件流上(本文内未实现)。  更为具体的介绍请自行google,必要注意的是命名对象的建立会和建立的进程相干。
方法流程和序次参数:
CreateFileMapping 第一位是一个文件的handle,如果用INVALID_HANDLE_VALUE将会使用默认的内存页文件作为映射。第二位是一个安全设置,为空的话会使用默认的安全控制表。第三位是读写权限和映射设置,支持OR操作。第三位是64位最大高位地址(为0,由于不会有这么大的文件)第四位是64位最大低位地址(未实际对象的物理内存长度)第五位是命名,为空是匿名对象,这里不讨论。

OpenFileMapping 第一位访问权限,第二位指定子进程是否可以共享该handle资源(涉及到handle的复制)。第三位就是命名。

MapViewOfFile第一位是上面两个方法得到的handle实例,第二位是访问权限,第三和第四位同CreateFileMapping意义上是视图相对的位移量。第五位是映射字节数,为0则映射整个建立块区。
从建立(或打开)映射开始,到建立视图,现在就可以在.net情况下使用对内存的读写了。
可以使用Marshal类的Copy方法,前面建立的安全handle上的DangerousGetHandle()方法将返回作业的安全指针。
handle是可以自释放的。

好了到告终束部分了,本来打算用这来实现某些功能,后来发现不太符合我的需求,结果这些代码就要被我废弃了,大抵上我看了十个不到的实现特例,此中以C++为主,而且这些作者都习惯性的作了包装类。
请看完这篇以后参考我的建议,不要在这之上再更多的去包装,对于简朴的数据传送和共享已经够了,我觉得毫无必要再繁琐下去加一个本身命名的class也不会突现什么万一设计不当反而会招人詈骂......当然如果刻意要做什么,除非你也往内里加了许多原子操作以及其他的同步作业控制,我也不能飞过来反对。就这样吧,盼望大家可以都学到知识。

最后这些方法和常量完全的颠末测试,请放心使用。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表