2.3 主程序和外部IO交互 (文件映射方式)----IO Server实现

2.3 主程序和外部IO交互 (文件映射方式)----IO Server C++实现

效果显示

1 内存共享概念

基本原理:以页面为单位,将一个普通文件映射到内存中,达到共享内存和节约内存的目的,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能

windows和linux都提供了原生的系统级的C++接口,可以将文件映射到内存

优点: 32位|64位 客户端都可以同时连接到Server上

1 参考资料 探索内存原理的内存映射文件(图文详解)

2 IO交互工作示意图

1 必须先打开IO Server 创建内存映射,然后打开IO Client才有效

2 IO Client 可以32位也可以64位

3 C++ 代码实现

3.1 shareddataServer.h 头文件中引用

尽量做到Windows |Linux 下都能够通用

c++ 复制代码
 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
 #define WIN32_LEAN_AND_MEAN             //  从 Windows 头文件中排除极少使用的信息
	#include <windows.h>
#elif defined(linux) || defined(__linux)
	#include <string.h>
	#include <sys/mman.h>
	#include <fcntl.h>
	#include <unistd.h> 
#endif 
3.2 shareddataServer.h 主要调用接口

在后面的测试中,我们主要演示DM8 来作为IO的 输入和输出

3.2.1 预定义变量名称,为了能够Linux|Windows下通用
cpp 复制代码
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)   

#elif defined(linux) || defined(__linux)
   typedef void *HANDLE;
   typedef void *LPVOID;
   typedef long long __int64;
    typedef __int64 LONG_PTR, *PLONG_PTR;
     typedef unsigned long long ULONG_PTR;
    typedef unsigned long long  *PULONG_PTR; 
    typedef int BOOL; 
   #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
#endif
3.2.2 接口定义
cpp 复制代码
BD_API  int  GetIOData(uchar* p_IOData, int start, int len);
BD_API  int  SetIOData(uchar* p_IOData, int start, int len);
BD_API  int  SetDM8(uchar* p_DM8, int start, int len);
BD_API  int  GetDM8(uchar* p_DM8, int start, int len);
BD_API  int  GetDM16(uchar* p_DM16, int start, int len);
BD_API  int  SetDM16(uchar* p_DM16, int start, int len); 


/**
 * ***********************************************************************************************
 * @brief ReleaseMMF
 * 销毁资源
 * 
 * @return BD_API 
 * ***********************************************************************************************
 */
BD_API void ReleaseMMF();
/**
 * ***********************************************************************************************
 * @brief 
 * 
 * 
 * @return BD_API 
 * ***********************************************************************************************
 */
BD_API int Create_Server();
3.3 shareddataServer.cpp 接口实现
3.3.0 MMF 句柄定义
cpp 复制代码
namespace SHAREDDATA
{ 
    #pragma region MMF 内存共享 IO 区
    // 创建共享文件句柄 
    HANDLE hMapFile_IO = INVALID_HANDLE_VALUE;
     // 文档句柄
    int  fd_io=-1;
    #pragma endregion MMF 内存IO 区
    #pragma region MMF 内存共享 DM8 区
    // 创建共享文件句柄 
    HANDLE hMapFile_DM8 = INVALID_HANDLE_VALUE;
    // 文档句柄
    int  fd_dm8=-1;
    #pragma endregion MMF 内存DM8 区
    #pragma region MMF 内存共享 DM16 区
    // 创建共享文件句柄 
    HANDLE hMapFile_DM16 = INVALID_HANDLE_VALUE;
   // 文档句柄
    int  fd_dm16=-1;
    #pragma endregion MMF 内存DM16 区
} 
                        
3.3.1 Create_Server()
cpp 复制代码
namespace SHAREDDATA
{ 
/**
 * ***********************************************************************************************
 * @brief 
 * Create_Server
 * 创建一个server
 * 
 * @return BD_API 
 * ***********************************************************************************************
 */
  BD_API int  Create_Server()
{
	int nRet = 0; 
	try
	{ 	
        #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
        // &0 DMIO
		hMapFile_IO = CreateFileMapping(
			INVALID_HANDLE_VALUE,   // 物理文件句柄
			NULL,   // 默认安全级别
			PAGE_READWRITE,   // 可读可写
			0,   // 高位文件大小
			n_max_IO_uchars,   // 低位文件大小
			"ShareMemoryIO"   // 共享内存名称
		);
		if (hMapFile_IO != INVALID_HANDLE_VALUE&&   hMapFile_IO > 0)nRet = 0;
		else return   -1;
		// &1 DM8
		hMapFile_DM8 = CreateFileMapping(
			INVALID_HANDLE_VALUE,   // 物理文件句柄
			NULL,   // 默认安全级别
			PAGE_READWRITE,   // 可读可写
			0,   // 高位文件大小
			n_max_DM8s,   // 低位文件大小
			"ShareMemoryDM8"   // 共享内存名称  
		);
		if (hMapFile_DM8 != INVALID_HANDLE_VALUE && hMapFile_DM8 > 0)nRet = 0;
		else return   -1;
		// &2 DM16
		hMapFile_DM16 = CreateFileMapping(
			INVALID_HANDLE_VALUE,   // 物理文件句柄
			NULL,   // 默认安全级别
			PAGE_READWRITE,   // 可读可写
			0,   // 高位文件大小
			n_max_DM16s,   // 低位文件大小
			"ShareMemoryDM16"   // 共享内存名称
		); 
 
 #elif defined(linux) || defined(__linux)
        // specify shared file path
	 // 路径一定要存在,否则会报警
       // &0 DMIO
	 string  shared_file_io = path+"ShareMemoryIO";
     fd_io = open(shared_file_io.c_str(), O_CREAT | O_RDWR | O_TRUNC, 00777);
	 if (fd_io < 0)
		{cout << "create file error" << endl;return -1;
        }
        ftruncate(fd_io, n_max_IO_uchars); // extend file size
     // map memory to file
	 //hMapFile_IO = mmap(NULL, 			n_max_IO_uchars,    , PROT_READ | PROT_WRITE, MAP_SHARED, fd_io, 0);     
            // &0 DM8
	 string shared_file_dm8 = path+"ShareMemoryDM8";
     fd_dm8 = open(shared_file_dm8.c_str(), O_CREAT | O_RDWR | O_TRUNC, 00777);
	 if (fd_dm8 < 0)
		{cout << "create file error" << endl;return -1;
        }
         ftruncate(fd_dm8, n_max_DM8s); // extend file size
     // map memory to file
	//hMapFile_DM8 = mmap(NULL, n_max_DM8s,    , PROT_READ | PROT_WRITE, MAP_SHARED, fd_dm8, 0);
      // &0 DM16
	 string shared_file_dm16= path+"ShareMemoryDM16";
     fd_dm16 = open(shared_file_dm8.c_str(), O_CREAT | O_RDWR | O_TRUNC, 00777);
	 if (fd_dm16 < 0)
		{cout << "create file error" << endl;return -1;
        }
     ftruncate(fd_dm16, n_max_DM16s); // extend file size  
 #endif
	}
	catch (exception& e)
	{
		nRet = -1;
	}
	return nRet;
}
#pragma region  销毁共享文件 句柄
// 销毁内存 MMF 句柄
BD_API void ReleaseMMF()
{
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)  
	if (hMapFile_IO != NULL)CloseHandle(hMapFile_IO);
	if (hMapFile_DM8 != NULL)CloseHandle(hMapFile_DM8);
	if (hMapFile_DM16 != NULL)CloseHandle(hMapFile_DM16); 
#elif defined(linux) || defined(__linux)

    if(fd_io>=0)close(fd_io);
    if(fd_dm8>=0)close(fd_dm8);
    if(fd_dm16>=0)close(fd_dm16);
      
#endif
} 
#pragma endregion  
}
3.3.2 重新定义MapViewofFile_New| UnMapViewofFile_New
cpp 复制代码
 LPVOID  MapViewofFile_New(HANDLE handle,const int& fd, const int& size) 
  {
    LPVOID lpBase=nullptr;
    if(handle==nullptr||size==0)return lpBase;
    #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)   

			// 映射缓存区视图 , 得到指向共享内存的指针
			  lpBase = MapViewOfFile(
				handle,            // 共享内存的句柄
				FILE_MAP_ALL_ACCESS, // 可读写许可
				0,
				0,
				size
			);
     #elif defined(linux) || defined(__linux)
        if(fd<0)return nullptr;
        	// map memory to file
     	lpBase = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     #endif

     return lpBase;
  }

  void  UnMapViewofFile_New(HANDLE handle,const int& size)
  {
   if(handle==nullptr||size==0)return ;
    #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)   

		 	// 解除文件映射
			UnmapViewOfFile(handle);
     #elif defined(linux) || defined(__linux)
        	// unmap and close
	    munmap(handle, size);
     #endif
     
     return;
  }
3.3.3 SetDM8|GetDM8 函数接口实现
cpp 复制代码
   /// @brief SetDM8
    /// @param p_DM8 
    /// @param start 
    /// @param len 
    /// @return 
    BD_API  int  SetDM8(uchar* p_DM8, int start, int len)
    {
        int nRet = 0;
        std::lock_guard<std::mutex> lock(_mutex);
        try
        {
            if (start > n_max_DM8s)
            {
                len = 0;
                nRet = -1;
                return nRet;
            }
            if (len + start > n_max_DM8s)
            {
                len = n_max_DM8s - start;
            }
            //  len 一定》0
            if (len > 0)
            {          
                // 映射缓存区视图 , 得到指向共享内存的指针
                LPVOID lpBase = MapViewofFile_New(hMapFile_DM8,fd_dm8,  n_max_DM8s);  
                memcpy((uchar*)lpBase + start, p_DM8, len);
                //memcpy(DM_8 + start, p_DM8, len);
                // 解除文件映射  
                UnMapViewofFile_New(lpBase, n_max_DM8s);
            }
            else nRet = -1;
        }
        catch (exception& e)
        {
            nRet = -1;
        }
        return nRet;
    }

    BD_API  int  GetDM8(uchar* p_DM8, int start, int len)
    {
        int nRet = 0;
        std::lock_guard<std::mutex> lock(_mutex);
        try
        {
            if (start > n_max_DM8s)
            {
                nRet = -1;
                return nRet;
            }
            if (len + start > n_max_DM8s)
            {
                len = n_max_DM8s - start;
            }
            //  len 一定》0
            if (len > 0)
            {
                if (hMapFile_DM8 == INVALID_HANDLE_VALUE)return -2;
                // 映射缓存区视图 , 得到指向共享内存的指针
                LPVOID lpBase = MapViewofFile_New(hMapFile_DM8,fd_dm8,  n_max_DM8s);                  
                // copy 内存
                memcpy(p_DM8, (uchar*)lpBase + start, len);
                //memcpy(p_DM8, DM_8 + start, len);
                // 解除文件映射
                UnMapViewofFile_New(lpBase, n_max_DM8s);                
            }
            else nRet = -1;
        }
        catch (exception& e)
        {
            nRet = -1;
        }
        return nRet;
    }
   
相关推荐
想胖的壮壮8 分钟前
python中的原子操作简介
开发语言·python
爱吃香菜¹9 分钟前
深入理解【 String类】
java·开发语言
LeoLei806024 分钟前
新特性之C++17
开发语言·c++
码农超哥同学32 分钟前
Python面试题:如何在 Python 中反转一个字符串?
开发语言·windows·python·面试·编程
不死鸟.亚历山大.狼崽子1 小时前
python库(2):Passlib库
开发语言·python
jllws11 小时前
C++基础:STL概述
开发语言·c++
FightingLod1 小时前
C++中list容器使用详解
开发语言·c++·list
Zucker n1 小时前
学会python——用python制作一个登录和注册窗口(python实例十八)
开发语言·python
mana飞侠1 小时前
代码随想录算法训练营第59天:动态[1]
开发语言·数据结构·算法·动态规划
艾恩小灰灰1 小时前
为何Web前端开发仍坚守 HTML 和 CSS,而不全然拥抱纯 JavaScript?
开发语言·前端·javascript·css·html·纯js