您当前的位置: 首页 > 

phymat.nico

暂无认证

  • 1浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

进程间通信 - 动态链接库实现

phymat.nico 发布时间:2015-01-10 16:24:38 ,浏览量:1


 
 

引子

前面介绍的几种用于实现进程之间通信的方法都是比较正统的方式,

像剪贴板,命名管道这些都还是用得比较多的,

而这里将介绍的是一种比较偏门的方法来实现进程间的通信,

所谓偏门呢,自然就是用的少,能够不用就不要使用。

其实这种方法就是通过动态链接库来实现进程间的通信。

          

                

动态链接库(DLL)概述              

既然是要通过动态链接库来实现进程间的通信,

那么这里如果不来介绍一下动态链接库的话,怎么也说不过去的。

动态链接库是 Windows 操作系统的基础,其中 Windows API 基本上都是以动态链接库的形式来提供的,

通常来说动态链接库是不能够直接运行,也不能够直接接受消息的,

它们是一些独立的文件(后缀名一般为 .dll ,当然还有其他的一些后缀名也是可以的),

其中包含能被可执行程序或其他 DLL 调用来完成某项工作的函数,

也就是说动态链接库也就是由一些函数组成而已。

并且只有在其他模块调用动态链接库中的函数时,动态链接库才发挥作用,

在实际的编程中,通常可以把完成某种功能的函数放在一个动态链接库中,然后提供给其他函数调用。

当这个访问了动态链接库的进程被加载时,系统会为这个进程分配 4GB 的私有地址空间,

然后系统就会分析这个可执行模块,找到这个可执行模块中所调用的 DLL ,然后系统就负责搜索这些 DLL ,

找到这些 DLL 后便将这些 DLL 加载到内存中,并为它们分配虚拟的内存空间,

最后将 DLL 的页面映射到调用进程的地址空间中,

DLL 的虚拟内存有代码页和数据页,它们被分别映射到 进程 A 的代码页面和数据页面,

如果这时 进程 B 也启动了,并且 进程 B 也需要访问该 DLL ,

这时,只需要将该 DLL 在虚拟内存中的代码页面和数据页面映射到第二个进程的地址空间即可。

这也表明了在内存中,只需要存在一份 DLL 的代码和数据,

多个进程共享 DLL 的同一份代码,很明显这样做可以节省内存空间的。

但是在 Windows 下,由于系统会为每一个进程分配 4GB 的私有地址空间,

而 DLL 中的代码和数据也只是映射到了这个私有地址空间中,所以这些应用程序之间还是不能够相互影响的,

也就是说多个应用程序虽然是可以共享同一个 DLL 中的相同的代码的,

但是 DLL 为每一个进程保存的数据都是不相同的,

并且每一个进程都为 DLL 使用的全部数据分配了自己的地址空间,

举个最简单的例子,我的 DLL 中有一个函数为 int   Add(int    num1 ,   int    num2),

这个函数的作用是实现 num1  和 num2 相加并返回相加后的结果。

然后我有一个 进程 A  使用了这个 DLL ,并且其调用了函数  Add(10, 20),

然后我还有一个 进程 B 其也使用了这个 DLL ,并且其调用了函数 Add(30, 40),

那么对于 进程 A 中的数据 10 和 20 其实是保存在 进程 A 的私有地址空间中的,

而对于 进程 B 中的数据 30 和 40 则是保存在 进程 B 的私有地址空间中的,

上面这个简单的例子表明如果单单用这种简单的使用动态链接库的方式是不能够实现进程之间的通信的。

      

          

动态链接库中共享内存的实现

如果想利用动态链接库来实现进程间的通信的话,那么有一种方案可以试一试,

即从系统为动态链接库分配的那一块内存(系统需要将动态链接库加载到内存中)下手,

由于在内存中,动态链接库其实只存在一份,

其被所有需要调用该动态链接库中的函数的模块或者简单说是可执行程序所共享,

既然是共享的话,如果我在系统给动态链接库分配的这块内存中保存数据,

那岂不是可以被所有访问该动态链接库的可执行程序所获取或者说设置。

这样的话,我就可以使用 进程 A 来设置好这个共享内存中的数据,

然后 进程 B 就可以读取这个共享内存中的数据了,这不是也可以实现进程间的通信嘛,

这样看来的话,其思路其实和使用剪贴板是一模一样的了。

也是采用一块两个进程共享的内存来作为存放数据的中介。

                  

          

示例:动态链接库实现进程间通信

共享 DLL 实现:

新建动态链接库项目步骤:

image

QQ截图未命名q

项目结构:

image

ShareDLL.h

#ifndef SHARED_DLL
#define SHARED_DLL
 
//在 DLL 项目中设置 DLL_API 为导出类型 extern "C" _declspec(dllimport)
//在 Test 项目中则无需设置该 DLL_API , 直接使用这个 CalculateDLL.h 文件即可
 
#ifdef DLL_API
#else 
    #define DLL_API extern "C" _declspec(dllimport)
#endif
 
DLL_API void SetData(int tmpData);
DLL_API int GetData();
 
#endif

         

DLL.cpp

// DLL.cpp : 定义 DLL 应用程序的导出函数。
//
 
#include "stdafx.h"
 
#define DLL_API extern "C" _declspec(dllexport)
 
#include "ShareDLL.h"
 
//使用 #pragma data_seg() 来表明这一段数据为共享数据
//一定要注意给下面的变量初始化,否则将无法实现数据在多个进程间共 享
#pragma data_seg("SharedDataInDll")
 
    //初始化为 0
    int data = 0;
 
#pragma data_seg()
 
 
//这里还需要告诉链接器表明 SharedDataInDll 数据段为可读可写可共享
#pragma comment(linker, "/SECTION:SharedDataInDll,RWS")
 
 
//返回共享数据
int GetData()
{
    return data;
}
 
//设置共享数据
void SetData(int tmpData)
{
    data = tmpData;
}

进程 A 实现:(简单 Console 程序)

项目结构:

image

ShareDLL.h

#ifndef SHARED_DLL
#define SHARED_DLL
 
//在 DLL 项目中设置 DLL_API 为导出类型 extern "C" _declspec(dllimport)
//在 Test 项目中则无需设置该 DLL_API , 直接使用这个 CalculateDLL.h 文件即可
 
#ifdef DLL_API
#else 
    #define DLL_API extern "C" _declspec(dllimport)
#endif
 
DLL_API void SetData(int tmpData);
DLL_API int GetData();
 
#endif
               

DLLProcessA.cpp

#include 
#include "ShareDLL.h"
 
using namespace std;
 
//引用 DLL.lib 引入库
#pragma comment(lib, "DLL.lib")
 
int main(int argc, char * argv)
{
    int data;
 
    coutdata;
 
    //设置共享内存
    SetData(data);
 
    cout            
关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0536s