- 浏览: 13385 次
最新评论
(转)进程通信机制
2010年07月30日
Windows 95进程间数据通讯的实现技术
1、引言
在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。WIN32 API提供了
许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进
程间的数据交换,就如同在WIN16中对本地进程进行读写操作一样。
典型的WIN16两进程可以通过共享内存来进行数据交换:(1)进程A将GlobalAlloc(GM
EM_SHARE...)API分配一定长度的内存;(2)进程A将GlobalAlloc函数返回的句柄传递
给进程B(通过一个登录消息);(3)进程B对这个句柄调用GlobalLock函数,并利用G
lobalLock函数返回的指针访问数据。这种方法在WIN32中可能失败,这是因为GlobalLo
ck函数返回指向的是进程A的内存,由于进程使用的是虚拟地址而非实际物理地址,因此
这一指针仅与A进程有关,而于B进程无关。
本文探讨了几种WIN32下进程之间通讯的几种实现方法,读者可以使用不同的方法以达到
程序运行高效可靠的目的。
2、Windows95中进程的内存空间管理
WIN32进程间通讯与Windows95的内存管理有密切关系,理解Windows95的内存管理对我们
如下的程序设计将会有很大的帮助,下面我们讨论以下Windows95中进程的内存空间管理
。
在WIN16下,所有Windows应用程序共享单一地址,任何进程都能够对这一空间中属于共
享单一的地址空间,任何进程都能够对这一空间中属于其他进程的内存进行读写操作,
甚至可以存取操作系统本身的数据,这样就可能破坏其他程序的数据段代码。
在WIN32下,每个进程都有自己的地址空间,一个WIN32进程不能存取另一个地址的私有
数据,两个进程可以用具有相同值的指针寻址,但所读写的只是它们各自的数据,这样
就减少了进程之间的相互干扰。另一方面,每个WIN32进程拥有4GB的地址空间,但并不
代表它真正拥有4GB的实际物理内存,而只是操作系统利用CPU的内存分配功能提供的虚
拟地址空间。在一般情况下,绝大多数虚拟地址并没有物理内存于它对应,在真正可以
使用这些地址空间之前,还要由操作系统提供实际的物理内存(这个过程叫"提交"co
mmit)。在不同的情况下,系统提交的物理内存是不同的,可能是RAM,也可能是硬盘模
拟的虚拟内存。
3、WIN32中进程间的通讯
在Windows 95中,为实现进程间平等的数据交换,用户可以有如下几种选择:
* 使用内存映射文件
* 通过共享内存DLL共享内存
* 向另一进程发送WM_COPYDATA消息
* 调用ReadProcessMemory以及WriteProcessMemory函数,用户可以发送由GlobalLock(
GMEM_SHARE,...)函数调用提取的句柄、GlobalLock函数返回的指针以及VirtualAlloc函
数返回的指针。
3.1、利用内存映射文件实现WIN32进程间的通讯
Windows95中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们
在WIN32进程中保留一段内存区域,把目标文件映射到这段虚拟内存中。在程序实现中必
须考虑各进程之间的同步。具体实现步骤如下:
首先我们在发送数据的进程中需要通过调用内存映射API函数CreateFileMapping创建一
个有名的共享内存:
HANDLE CreateFileMapping(
HANDLE hFile, // 映射文件的句柄,
//设为0xFFFFFFFF以创建一个进程间共享的对象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性
DWORD flProtect, // 保护方式
DWORD dwMaximumSizeHigh, //对象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 必须为映射文件命名
);
与虚拟内存类似,保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多进程都对
同一共享内存进行写访问,则必须保持相互间同步。映射文件还可以指定PAGE_WRITECO
PY标志,可以保证其原始数据不会遭到破坏,同时允许其他进程在必要时自由的操作数
据的拷贝。
在创建文件映射对象后使用可以调用MapViewOfFile函数映射到本进程的地址空间内。
下面说明创建一个名为MySharedMem的长度为4096字节的有名映射文件:
HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFF FFF),
NULL,PAGE_READWRITE,0,0x1000,"MySharedMem");
并映射缓存区视图:
LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedM apFile,
FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
其他进程访问共享对象,需要获得对象名并调用OpenFileMapping函数。
HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE,
FALSE,"MySharedMem");
一旦其他进程获得映射对象的句柄,可以象创建进程那样调用MapViewOfFile函数来映射
对象视图。用户可以使用该对象视图来进行数据读写操作,以达到数据通讯的目的。
当用户进程结束使用共享内存后,调用UnmapViewOfFile函数以取消其地址空间内的视图
:
if (!UnmapViewOfFile(pszMySharedMapView))
{ AfxMessageBox("could not unmap view of file"); }
3.2、利用共享内存DLL
共享数据DLL允许进程以类似于Windows 3.1 DLL共享数据的方式访问读写数据,多个进
程都可以对该共享数据DLL进行数据操作,达到共享数据的目的。在WIN32中为建立共享
内存,必须执行以下步骤:
首先创建一个有名的数据区。这在Visual C++中是使用data_seg pragma宏。使用data_
seg pragma宏必须注意数据的初始化:
#pragma data_seg("MYSEC")
char MySharedData[4096]={0};
#pragma data_seg()
然后在用户的DEF文件中为有名的数据区设定共享属性。
LIBRARY TEST
DATA READ WRITE
SECTIONS
.MYSEC READ WRITE SHARED
这样每个附属于DLL的进程都将接受到属于自己的数据拷贝,一个进程的数据变化并不会
反映到其他进程的数据中。
在DEF文件中适当地输出数据。以下的DEF文件项说明了如何以常数变量的形式输出MySh
aredData。
EXPORTS
MySharedData CONSTANT
最后在应用程序(进程)按外部变量引用共享数据。
extern _export"C"{char * MySharedData[];}
进程中使用该变量应注意间接引用。
m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED);
m_pStatic->GetLine(0,*MySharedData,80);
3.3、用于传输只读数据的WM_COPYDATA
传输只读数据可以使用Win32中的WM_COPYDATA消息。该消息的主要目的是允许在进程间
传递只读数据。Windows95在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SD
K文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送方就
不可能删除和修改数据:
SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT{
DWORD dwData;//用户定义数据
DWORD cbData;//数据大小
PVOID lpData;//指向数据的指针
}COPYDATASTRUCT;
该结构用来定义用户数据。
3.4、直接调用ReadProcessMemory和WriteProcessMemory函数实现进程间通讯
通过调用ReadProcessMemory以及WriteProcessMemory函数用户可以按类似与Windows3.
1的方法实现进程间通讯,在发送进程中分配一块内存存放数据,可以调用GlobalAlloc
或者VirtualAlloc函数实现:
pApp->m_hGlobalHandle=GlobalAlloc(GMEM_SHARE,1024);
可以得到指针地址:
pApp->mpszGlobalHandlePtr=(LPSTR)GlobalLock
(pApp->m_hGlobalHandle);
在接收进程中要用到用户希望影响的进程的打开句柄。为了读写另一进程,应按如下方
式调用OpenProcess函数:
HANDLE hTargetProcess=OpenProcess(
STANDARD_RIGHTS_REQUIRED|
PROCESS_VM_REDA|
PROCESS_VM_WRITE|
PROCESS_VM_OPERATION,//访问权限
FALSE,//继承关系
dwProcessID);//进程ID
为保证OpenProcess函数调用成功,用户所影响的进程必须由上述标志创建。
一旦用户获得一个进程的有效句柄,就可以调用ReadProcessMemory函数读取该进程的内
存:
BOOL ReadProcessMemory(
HANDLE hProcess, // 进程指针
LPCVOID lpBaseAddress, // 数据块的首地址
LPVOID lpBuffer, // 读取数据所需缓冲区
DWORD cbRead, // 要读取的字节数
LPDWORD lpNumberOfBytesRead
);
使用同样的句柄也可以写入该进程的内存:
BOOL WriteProcessMemory(
HANDLE hProcess, // 进程指针
LPVOID lpBaseAddress, // 要写入的首地址
LPVOID lpBuffer, // 缓冲区地址
DWORD cbWrite, // 要写的字节数
LPDWORD lpNumberOfBytesWritten
);
如下所示是读写另一进程的共享内存中的数据:
ReadProcessMemory((HANDLE)hTargetProcess,
(LPSTR)lpsz,m_strGlobal.GetBuffer(_MAX_FIELD),
_MAX_FIELD,&cb);
WriteProcessMemory((HANDLE)hTargetProcess,
(LPSTR)lpsz,(LPSTR)STARS,
m_strGlobal.GetLength(),&cb);
4、进程之间的消息发送与接收
在实际应用中进程之间需要发送和接收Windows消息来通知进程间相互通讯,发送方发送
通讯的消息以通知接收方,接收方在收到发送方的消息后就可以对内存进行读写操作。
我们在程序设计中采用Windows注册消息进行消息传递,首先在发送进程初始化过程中进
行消息注册:
m_nMsgMapped=::RegisterWindowsMessage("Mapped");
m_nMsgHandle=::RegisterWindowsMessage("Handle");
m_nMsgShared=::RegisterWindowsMessage("Shared");
在程序运行中向接收进程发送消息:
CWnd* pWndRecv=FindWindow(lpClassName,"Receive");
pWndRecv->SendMessage(m_MsgMapped,0,0);
pWndRecv->SendMessage(m_nMsgHandle,
(UINT)GetCurrentProcessID(),(LONG)pApp->m_hGlobalHa ndle);
pWndRecv->SendMessage(m_nMsgShared,0,0);
可以按如下方式发送WM_COPYDATA消息:
static COPYDATASTRUCT cds;//用户存放数据
pWnd->SendMessage(WM_COPYDATA,NULL,(LONG)&cds);
接收方进程初始化也必须进行消息注册:
UNIT CRecvApp:: m_nMsgMapped=::RegisterWindowsMessage("Mapped");
UNIT CRecvApp::m_nMsgHandle=::RegisterWindowsMessage("H andle");
UNIT CRecvApp::m_nMsgShared=::RegisterWindowsMessage("S hared");
同时映射消息函数如下:
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgMapped,OnReg MsgMapped)
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgHandle,OnReg MsgHandle)
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgShared,OnReg MsgShared)
在这些消息函数我们就可以采用上述技术实现接收进程中数据的读写操作了。
5、结束语
从以上分析中我们可以看出Windows95的内存管理与Windows 3.x相比有很多的不同,对
进程之间的通讯有较为严格的限制。这就确保了任何故障程序无法意外地写入用户的地
址空间,而用户则可根据实际情况灵活地进行进程间的数据通讯,从这一点上来讲Wind
ows95增强应用程序的强壮性。
参考文献:
1、 David J.Kruglinski, Visual C++技术内幕, 北京:清华大学出版社,1995.
2、 Microsoft Co. Visual C++ 5.0 On Line Help.
发表评论
-
alsa声音编程介绍
2012-01-20 08:56 1114alsa声音编程介绍 2011年02月01日 英文原文: ... -
linux内核空间与用户空间信息交互方法
2012-01-20 08:55 589linux内核空间与用户空 ... -
Linux学习笔记(linux 0.11完全注释)
2012-01-20 08:55 1097Linux学习笔记(linux 0.11完全注释) 2010 ... -
连傻瓜都能看懂的基于代码注入的线程守护技术
2012-01-20 08:55 1027连傻瓜都能看懂的基于 ... -
as3面试题
2012-01-19 14:00 832as3面试题 2011年09月13日 ... -
AS3 框架 不断更新
2012-01-19 14:00 591AS3 框架 不断更新 2011 ... -
只学一点点:我的技术学习策略
2012-01-19 14:00 575只学一点点:我的技术学 ... -
使用ArcGIS API for Flex开发的地图应用网站
2012-01-19 14:00 954使用ArcGIS API for Flex开发的地图应用网站 ... -
Flex工程里TextField在fp10.1下不能输入中文的解决办法
2012-01-19 14:00 566Flex工程里TextField在fp10.1下不能输入中文的 ... -
了解进程中的内存结构
2012-01-17 03:50 524了解进程中的内存结构 ... -
内存映射与DMA笔记
2012-01-17 03:50 730内存映射与DMA笔记 2011 ... -
0x00000000内存出错 内存不能为read
2012-01-17 03:50 8040x00000000内存出错 内存不能为read 2010年 ... -
应该用程序错误 该内存不能为“read”的几个解决方法
2012-01-17 03:50 744应该用程序错误 该内存不能为“read”的几个解决方法 20 ... -
0x1001240”指令引用的“0x10001240”内存。该内存不能为“read”要终止程序,请单击“确定”。
2012-01-17 03:50 7180x1001240”指令引用的“0x10001240”内存。该 ... -
发动机
2012-01-16 02:35 744发动机 2010年01月13日 ... -
汽车钣金维修工艺
2012-01-16 02:35 1224汽车钣金维修工艺 2009年09月26日 汽车钣金维修工 ...
相关推荐
操作系统实验二:进程通信机制的应用实验报告。加深对于进程并发执行概念的理解。实践并发进/线程的创 建和控制方法。观察和体验进程的动态特性。进一步理解进程生命期期间创建、变换、撤销状态变换的过程。掌握进程...
由于传统IPC机制和远程互操作体系并不适应桌面进程通信的要求,因此在开放系统领域中处于主流地位的桌面系统GNOME和KDE分别采用CORBA和DCOP作为桌面进程通信机制。一种新的用于统一各个不同桌面的进程通信机制DBUS...
Android 进程间通信机制 (Binder) 介绍
分别利用UNIX的消息通信机制、共享内存机制(用信号灯实施进程间的同步和互斥)实现两个进程间的数据通信。具体的通信数据可从一个文件读出,接收方进程可将收到的数据写入一个新文件,以便能判断数据传送的正确性。
北京大学操作系统 进程通信机制
本文首先对Linux的进程结构、进程调度等问题进行分析。接着对Linux操作系统进程间通信机制全面深入的论述
java进程间通信机制.ppt
基于源代码和清晰的流程图,详细讲解了linux的进程间通信机制
总结:跨进程访问Activity(访问其他应用程序中的Activity)主要是通过一个Action来完成的,如果要传递数据,还需要指定一个Uri。当然,传递数据也可以通过Intent来完成。传递数据的过程可以是双向的。如果要想从...
进程在核心的协调下进行相互间的通讯机制——管道,信号量,消息队列。
学习利用管道机制实现进程间的通信,加深对通信机制的理解。 实验内容: 1、 了解系统调用pipe()的功能和实际原理 2、 编写一段程序,使用管道实现父子进程之间的通信 a) 使用系统调用fork()创建一个子进程 b) 子...
共享内存,进程通信,进程同步 源代码 vs2005
LINUX系统编程下进程间通信机制,pdf格式,对理解进程间的通信很重要
进程间通信机制——China.pub.com
计算机操作系统实验-进程通信(一)
操作系统 进程通信 VC++代码 用户界面
分别利用UNIX的消息通信机制、共享内存机制(要用信号灯实施进程间的同步和互斥)实现两个进程间的数据通信。具体的通信数据可从一个文件读出,接收方进程可将收到的数据写入一个新文件,以便能判断数据传送的正确性...
计算机操作系统实验-进程通信(二)
其中管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因 此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 认清管道和有名管道...
Linux中System V进程通信机制安全性形式化验证.pdf