windows下进程通讯的几种方法
- 1 Windows进程间通讯的各类方法
-
- 进程是装入内存并准备执行的程序,每一个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。
- 多进程/多线程是Windows操做系统的一个基本特征。Microsoft Win32应用编程接口(Application Programming Interface, API)
- 提供了大量支持应用程序间数据共享和交换的机制,这些机制行使的活动称为进程间通讯(InterProcess Communication, IPC),
- 进程通讯就是指不一样进程间进行数据共享和数据交换。
- 正由于使用Win32 API进行进程通讯方式有多种,如何选择恰当的通讯方式就成为应用开发中的一个重要问题,
- 下面本文将对Win32中进程通讯的几种方法加以分析和比较。
-
-
- 2 进程通讯方法
-
- 2.1 文件映射
-
- 文件映射(Memory-Mapped Files)能使进程把文件内容看成进程地址区间一块内存那样来对待。所以,进程没必要使用文件I/O操做,
- 只需简单的指针操做就可读取和修改文件的内容。
- Win32 API容许多个进程访问同一文件映射对象,各个进程在它本身的地址空间里接收内存的指针。经过使用这些指针,不一样进程就能够读或修改文件的内容,
- 实现了对文件中数据的共享。
- 应用程序有三种方法来使多个进程共享一个文件映射对象。
- (1)继承:第一个进程创建文件映射对象,它的子进程继承该对象的句柄。
- (2)命名文件映射:第一个进程在创建文件映射对象时能够给该对象指定一个名字(可与文件名不一样)。第二个进程可经过这个名字打开此文件映射对象。
- 另外,第一个进程也能够经过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。
- (3)句柄复制:第一个进程创建文件映射对象,而后经过其它IPC机制(有名管道、邮件槽等)把对象句柄传递给第二个进程。
- 第二个进程复制该句柄就取得对该文件映射对象的访问权限。
- 文件映射是在多个进程间共享数据的很是有效方法,有较好的安全性。但文件映射只能用于本地机器的进程之间,不能用于网络中
- ,而开发者还必须控制进程间的同步。
-
- 2.2 共享内存
-
- Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊状况。进程在建立文件映射对象时用0xFFFFFFFF来代替 文件句柄(HANDLE),
-
- 就表示了对应的文件映射对象是从操做系统页面文件访问内存,其它进程打开该文件映射对象就能够访问该内存块。因为共享内存是用 文件映射实现的,
- 因此它也有较好的安全性,也只能运行于同一计算机上的进程之间。
-
- a.设定一块共享内存区域
-
- HANDLE CreateFileMapping(HANDLE,LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR)// 产生一个file-mapping核心对象
- LPVOID MapViewOfFile(
- HANDLE hFileMappingObject,
- DWORD dwDesiredAcess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- DWORD dwNumberOfBytesToMap
- );获得共享内存的指针
-
- b.找出共享内存
- 决定这块内存要以点对点(peer to peer)的形式呈现每一个进程都必须有相同的能力,产生共享内存并将它初始化。每一个进程都应该调用CreateFileMapping(),
-
- 而后调用GetLastError().若是传回的错误代码是 ERROR_ALREADY_EXISTS,那么进程就能够假设这一共享内存区 域已经被别的进程打开并初始化了,
-
- 不然该进程就能够合理的认为本身 排在第 一位,并接下来将共享内存初始化。仍是要使用client/server架构中只有server进程才应该产生并初始化共享内存。
- 全部的进程都应该使用
- HANDLE OpenFileMapping(DWORD dwDesiredAccess,
- BOOL bInheritHandle,
- LPCTSTR lpName);
- 再调用MapViewOfFile(),取得共享内存的指针
-
-
- c.同步处理(Mutex)
-
-
- d.清理(Cleaning up) BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);
-
- CloseHandle()
-
-
- 2.3 匿名管道
- 管道(Pipe)是一种具备两个端点的通讯通道:有一端句柄的进程能够和有另外一端句柄的进程通讯。管道能够是单向-一端是只读的,另外一端点是只写的;
- 也能够是双向的一管道的两端点既可读也可写。
-
- 匿名管道(Anonymous Pipe)是 在父进程和子进程之间,或同一父进程的两个子进程之间传输数据的无名字的单向管道。一般由父进程建立管 道,
-
- 而后由要通讯的子进程继承通道的读端点句柄或写 端点句柄,而后实现通讯。父进程还能够创建两个或更多个继承匿名管道读和写句柄的子进程。
- 这些子进程 可使用管道直接通讯,不须要经过父进程。
- 匿名管道是单机上实现子进程标准I/O重定向的有效方法,它不能在网上使用,也不能用于两个不相关的进程之间。
-
- 2.4 命名管道
- 命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通讯的单向或双向管道。不一样于匿名管道的是命名管道能够在不相关的进程之间和不 同计算机之间使用,
- 服务器创建命名管道时给它指定一个名字,任何进程均可以经过该名字打开管道的另外一端,根据给定的权限和服务器进程通讯。
- 命名管道提供了相对简单的编程接口,使经过网络传输数据并不比同一计算机上两进程之间通讯更困难,不过若是要同时和多个进程通讯它就力不从心了。
-
- 2.5 邮件槽
- 邮件槽(Mailslots)提 供进程间单向通讯能力,任何进程都能创建邮件槽成为邮件槽服务器。其它进程,称为邮件槽客户,能够经过邮件槽的名字给
- 邮件槽服务器进程发送消息。进来的消 息一直放在邮件槽中,直到服务器进程读取它为止。一个进程既能够是邮件槽服务器也能够是邮件槽客户,
- 所以可创建多个 邮件槽实现进程间的双向通讯。
- 经过邮件槽能够给本地计算机上的邮件槽、其它计算机上的邮件槽或指定网络区域中全部计算机上有一样名字的邮件槽发送消息。
- 广播通讯的消息长度不能超过400字节,非广播消息的长度则受邮件槽服务器指定的最大消息长度的限制。
- 邮件槽与命名管道类似,不过它传输数据是经过不可靠的数据报(如TCP/IP协议中的UDP包)完成的,一旦网络发生错误则没法保证消息正确地接收,
- 而 命名管道传输数据则是创建在可靠链接基础上的。不过邮件槽有简化的编程接口和给指定网络区域内的全部计算机广播消息的能力,
- 因此邮件槽不失为应用程序发送 和接收消息的另外一种选择。
-
- 2.6 剪贴板
- 剪贴板(Clipped Board)实质是Win32 API中一组用来传输数据的函数和消息,为Windows应用程序之间进行数据共享提供了一个 中介,
- Windows已创建的剪切(复制)-粘贴的机制为不一样应用程序之间共享不一样格式数据提供了一条捷径。当用户在应用程序中执行剪切或复制操做时,
- 应 用程序把选取的数据用一种或多种格式放在剪贴板上。而后任何其它应用程序均可以从剪贴板上拾取数据,从给定格式中选择适合本身的格式。
- 剪贴板 是一个很是松散的交换媒介,能够支持任何数据格式,每一格式由一无符号整数标识,对标准(预约义)剪贴板格式,该值是Win32 API定义的常量;
- 对非 标准格式可使用Register Clipboard Format函数注册为新的剪贴板格式。利用剪贴板进行交换的数据只需在数据格式上一致或均可以
- 转化为某种格式就行。但剪贴板只能在基于Windows的程序中使用,不能在网络上使用。
-
-
-
- 2.7 动态数据交换
- 动态数据交换(DDE)是使用共享内存在应用程序之间进行数据交换的一种进程间通讯形式。应用程序可使用DDE进行一次性数据传输,也能够当出现新数据时,
- 经过发送更新值在应用程序间动态交换数据。
- DDE和剪贴板同样既支持标准数据格式(如文本、位图等),又能够支持本身定义的数据格式。但它们的数据传输机制却不一样,一个明显区别是剪贴板操做几乎
- 老是用做对用户指定操做的一次性应答-如从菜单中选择Paste命令。尽管DDE也能够由用户启动,但它继续发挥做用通常没必要用户进一步干预。DDE有三 种数据交换方式:
- (1) 冷链:数据交换是一次性数据传输,与剪贴板相同。
- (2) 温链:当数据交换时服务器通知客户,而后客户必须请求新的数据。
- (3) 热链:当数据交换时服务器自动给客户发送数据。
- DDE交换能够发生在单机或网络中不一样计算机的应用程序之间。开发者还能够定义定制的DDE数据格式进行应用程序之间特别目的IPC,它们有更紧密耦合的通讯要求。
- 大多数基于Windows的应用程序都支持DDE。
-
- 2.8 对象链接与嵌入
- 应用程序利用对象链接与嵌入(OLE)技术管理复合文档(由多种数据格式组成的文档),OLE提供使某应用程序更容易调用其它应用程序进行数据编辑的服 务。
- 例如,OLE支持的字处理器能够嵌套电子表格,当用户要编辑电子表格时OLE库可自动启动电子表格编辑器。当用户退出电子表格编辑器时,
- 该表格已在原 始字处理器文档中获得更新。在这里电子表格编辑器变成了字处理器的扩展,而若是使用DDE,用户要显式地启动电子表格编辑器。
- 同DDE技术相同,大多数基于Windows的应用程序都支持OLE技术。
-
- 2.9 动态链接库
- Win32动态链接库(DLL)中的全局数据能够被调用DLL的全部进程共享,这就又给进程间通讯开辟了一条新的途径,固然访问时要注意同步问题。
- 虽然能够经过DLL进行进程间数据共享,但从数据安全的角度考虑,咱们并不提倡这种方法,使用带有访问权限控制的共享内存的方法更好一些。
-
- 2.10 远程过程调用
- Win32 API提供的远程过程调用(RPC)使应用程序可使用远程调用函数,这使在网络上用RPC进行进程通讯就像函数调用那样简单。
- RPC既能够在单机不一样进程间使用也能够在网络中使用。
- 因为Win32 API提供的RPC服从OSF-DCE (Open Software Foundation Distributed Computing Environment)标准。
- 因此经过 Win32 API编写的RPC应用程序能与其它操做系统上支持DEC的RPC应用程序通讯。使用RPC开发者能够创建高性能、紧密耦合的分布式应用程 序。
-
- 2.11 NetBios函数
- Win32 API提供NetBios函数用于处理低级网络控制,这主要是为IBM NetBios系统编写与Windows的接口。除非那些有特殊低级网络功能要求的应用程序,
- 其它应用程序最好不要使用NetBios函数来进行进程间通讯。
-
- 2.12 Sockets
- Windows Sockets规范是以U.C.Berkeley大学BSD UNIX中流行的Socket接口为范例定义的一套Windows下的网 络编程接口。除了Berkeley Socket原有的库函数之外
- ,还扩展了一组针对Windows的函数,使程序员能够充分利用Windows的消息机 制进行编程。
- 如今经过Sockets实现进程通讯的网络应用愈来愈多,这主要的缘由是Sockets的跨平台性要比其它IPC机制好得多,另 外WinSock 2.0不只支持TCP/IP协议,
- 并且还支持其它协议(如IPX)。Sockets的惟一缺点是它支持的是底层通讯操做,这使得在单机 的进程间进行简单数据传递不太方便,
- 这时使用下面将介绍的WM_COPYDATA消息将更合适些。
-
- 2.13 WM_COPYDATA消息
- WM_COPYDATA是一种很是强大却不为人知的消息。当一个应用向另外一个应用传送数据时,发送方只需使用调用SendMessage函数,
- 参数是目 的窗口的句柄、传递数据的起始地址、WM_COPYDATA消息。接收方只需像处理其它消息那样处理WM_COPY DATA消息,这样收发双方就实现了 数据共享。
- WM_COPYDATA是一种很是简单的方法,它在底层其实是经过文件映射来实现的。
-
- 它的缺点是灵活性不高,而且它只能用于Windows平台的单机环境下。
-
- 3 结束语
-
- Win32 API为应用程序实现进程间通讯提供了如此多种选择方案,
- 那么开发者如何进行选择呢?一般在决定使用哪一种IPC方法以前应考虑如下一些问题:
- (1)应用程序是在网络环境下仍是在单机环境下工做。
-
- 方法一:WM_COPYDATA
- HWND hReceiveDataWindow = FindWindow(NULL,....)
- COPYDATASTRUCT data;
- data.cbdata = strlen(pStr);
- data.lpData = pStr;
- SendMessage(hReceiveDataWindow ,WM_COPYDATA,(WPARAM)GetFocus(),(LPARAM)&data);
- REF.最简单的方式
- http://www.cppblog.com/TechLab/archive/2005/12/30/2272.aspx
-
-
- 方法二:dll共享
- #pragma data_seg (".ASHARE")
- int iWhatYouUseInTwo = 0;
- #pragma data_seg()
-
-
- 方法三:映象文件
- REF.最基础,效率最高的方法
- 最好的参考书《Windows核心编程》第17章 内存映射文件
- http://blog.codingnow.com/2005/10/interprocess_communications.html
-
- 方法四:匿名管道:CreatePipe
- 方法五:命名管道:createnamedpipe
- REF.
- http://www.pediy.com/bbshtml/bbs8/pediy8-724.htm
-
- 方法六:邮件通道
-
- 方法七:网络接口,socket,但要求有网卡。能够实现不一样主机间的IPC
- 另外一篇总结的比较好的文章
- http://www.seeitco.com/doc/Html/Visual%20C++/205637623.html
-
-
- 进程一般被定义为一个正在运行的程序的实例,它由两个部分组成:
- 一个是操做系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程的统计信息的地方
- 另外一个是地址空间,它包含全部的可执行模块或DLL模块的代码和数据。它还包含动态分配的空间。
- 如线程堆栈和堆分配空间。每一个进程被赋予它本身的虚拟地址空间,当进程中的一个线程正在运行时,该线程能够访问只属于它的进程的内存。
- 属于其它进程的内存则是隐藏的,并不能被正在运行的线程访问。
- 为了能在两个进程之间进行通信,由如下几种方法可供参考:
-
- 0。剪贴板Clipboard: 在16位时代常使用的方式,CWnd中提供支持
-
- 1。窗口消息 标准的Windows消息以及专用的WM_COPYDATA消息 SENDMESSAGE()接收端必须有一个窗口
-
- 2。使用共享内存方式(Shared Memory)
- a.设定一块共享内存区域
- HANDLE CreateFileMapping(HANDLE,LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR)
- 产生一个file-mapping核心对象
- LPVOID MapViewOfFile(
- HANDLE hFileMappingObject,
- DWORD dwDesiredAcess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- DWORD dwNumberOfBytesToMap
- );
- 获得共享内存的指针
- b.找出共享内存
- 决定这块内存要以点对点(peer to peer)的形式呈现
- 每一个进程都必须有相同的能力,产生共享内存并将它初始化。每一个进程
- 都应该调用CreateFileMapping(),而后调用GetLastError().若是传回的
- 错误代码是ERROR_ALREADY_EXISTS,那么进程就能够假设这一共享内存区 域已经被别的进程打开并初始化了,不然该进程就能够合理的认为本身 排在第 一位,并接下来将共享内存初始化。
- 仍是要使用client/server架构中
- 只有server进程才应该产生并初始化共享内存。全部的进程都应该使用
-
- HANDLE OpenFileMapping(DWORD dwDesiredAccess,
- BOOL bInheritHandle,
- LPCTSTR lpName);
- 再调用MapViewOfFile(),取得共享内存的指针
- c.同步处理(Mutex)
- d.清理(Cleaning up) BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);
- CloseHandle()
-
- 3。动态数据交换(DDE)经过维护全局分配内存使的应用程序间传递成为可能
- 其方式是再一块全局内存中手工放置大量的数据,而后使用窗口消息传递内存 指针.这是16位WIN时代使用的方式,由于在WIN32下已经没有全局和局部内存
- 了,如今的内存只有一种就是虚存。
-
- 4。消息管道(Message Pipe)
- 用于设置应用程序间的一条永久通信通道,经过该通道能够象本身的应用程序
- 访问一个平面文件同样读写数据。
- 匿名管道(Anonymous Pipes)
- 单向流动,而且只可以在同一电脑上的各个进程之间流动。
- 命名管道(Named Pipes)
- 双向,跨网络,任何进程均可以轻易的抓住,放进管道的数据有固定的格 式,而使用ReadFile()只能读取该大小的倍数。
- 能够被使用于I/O Completion Ports
-
- 5 邮件槽(Mailslots)
- 广播式通讯,在32系统中提供的新方法,能够在不一样主机间交换数据,在 WIN9X下只支持邮件槽客户
-
- 6。Windows套接字(Windows Socket)
- 它具有消息管道全部的功能,但遵照一套通讯标准使的不一样操做系统之上的应 用程序之间能够互相通讯。
-
- 7。Internet通讯 它让应用程序从Internet地址上载或下载文件
-
- 8。RPC:远程过程调用,不多使用,因其与UNIX的RPC不兼容。
-
- 9。串行/并行通讯(Serial/Parallel Communication)
- 它容许应用程序经过串行或并行端口与其余的应用程序通讯
-
- 10。COM/DCOM
-
- 经过COM系统的代理存根方式进行进程间数据交换,但只可以表如今对接口
-
- 函数的调用时传送数据,经过DCOM能够在不一样主机间传送数据。
欢迎关注本站公众号,获取更多信息