`
T240178168
  • 浏览: 367397 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

进程间通信:Windows下进程间通信的手段

    博客分类:
  • java
阅读更多
1 进程与进程通信
  进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。多进程/多线程是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),就表示了对应的文件映射对象是从操作系统页面文件访问内存,其它进程打开该文件映射对象就可以访问该内存块。由于共享内存是用文件映射实现的,所以它也有较好的安全性,也只能运行于同一计算机上的进程之间。
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
套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。


多进程通信方式一:管道(PIPE) 收藏
进程通信(IPC)的几种方式及比较
撰文:黄显国080416

难得闲暇,抽空学习了一下进程通信的知识,现将这几天的所学做一下总结,以备遗忘时参考。

进程通信的方式:
Linux系统继承了三种系统的进程通信模式:
1、 基于system V IPC
2、 基于UNIX IPC
3、  基于POSIX IPC
同时还包含一种socket进程间通信,不过这种是不同处理器系统之间的一种网络通信方式,不是我所关心的。

方式一:管道(PIPE)
管道分无名管道与有名管道两种
1、  无名管道。
无名管道用于具有亲缘关系的父子进程,子子进程之间的通讯。它的实现函数有
int pipe(int fd[2]);
//fd[2]为描述符数组,包含一个读描述符与一个写描述符,在使用管道通信时,关闭某些不需要的读或写描述符,建立起单向的读或写管道,然后用read和write像操作文件一样去操作它即可。

如图便是进程1到进程2的一个读管道。

以下是我写的一个pipe的验证程序,分别在父进程和父子进程里向管道写数据,然后在子进程和子子进程里读数据,当尝试改变各子进程的sleep时间以实现渴望的同步时,会发现结果很有趣。注意创建子进程时将复制父进程的管道。

/*******************************************************************************************/
//pipe.c
//frome the example, we can see:
//用pipe创建的无名管道,父子进程,子子进程之间都可以通信,由于read
//或write默认为阻塞,而进程与进程之间又有某种意义上的同步方法;
//故而可以从下面的程序中得到一些启示。
/*****************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main()
{
       int pipe_fd[2];
       char buf_r[100];
       char buf_rr[100];
       if(pipe(pipe_fd)<0)
       {
              printf("pipe create error\n");
              return -1;
       }
       else
              printf("pipe create success\n");
       printf("pipe_fd[0]=%d,pipe_fd[1]=%d\n",pipe_fd[0],pipe_fd[1]);
      
       if(fork()==0)//子进程
       {
              close(pipe_fd[1]);//关闭子进程的写描述符
              printf("fork()");
              //sleep(2);
              if(fork()==0)//子子进程
              {    
                     if(read(pipe_fd[0],buf_r,5)>0)
                            printf("BUF_R: in child child process,read from the pipe is %s\n",buf_r); 
                     close(pipe_fd[0]);
                     exit(0);
              }
              Else //子进程
              {
                     if(read(pipe_fd[0],buf_rr,3)>0)
                            printf("BUF_RR: in child parent process,read from the pipe is %s\n",buf_rr);
                     close(pipe_fd[0]);
                     exit(0);   
              }
       }
       else  //父进程
       {
              close(pipe_fd[0]);
              sleep(5);
              if(write(pipe_fd[1],"Hello ",5)!=-1)
                     printf("write1 parent pipe success\n"); 
              if(fork()==0)  //父子进程
              {
                     if(write(pipe_fd[1],"PIPE",5)!=-1)
                            printf("write parent child pipe success");     
                     close(pipe_fd[1]);  
                     exit(0);   
              }
              close(pipe_fd[1]);
              exit(0);
       }
}

2、  有名管道
有名管道可用于两个无关的进程之间的通信。它的实现函数是:
int mkfifo(const char *filename, mode_t mode)
//创建一个名为filename的管道,模式可选为读或写方式,阻塞或非阻塞方式等。
下面一个实例演示了mkfifo的使用。Fifo_read.c不断从管道文件里读数据,fifo_write.c往管道文件里写数据。改变sleep的值也会产生类似上面进程同步的问题,而会发现一些缓冲区的特性。
两个程序用gcc编译后在两个终端里运行。
//---------------------------------------------------------------------------------------------------
//fifo_read.c
//创建有名管道,演示两个不相关的进程之间的通信
//int mkfifo(const char *filename, mode_t mode)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#define FIFO "/home/huang/myfifo"

int main(int argc,char **argv)
{
       int fd;
       int nread;
       char buf_r[100];
       if(mkfifo("/home/huang/myfifo",O_CREAT|O_EXCL)<0)//&&(errno!=EEXIST))
       {
              perror("mkfifo:");
              printf("cann't create fifoserver\n");
              return -1;
       }
       printf("Preparing for reading bytes...\n");
       fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
       if(fd==-1)
       {
              perror("open!\n");
              exit(1);
       }
       while(1)
       {
              memset(buf_r,0,sizeof(buf_r));
              if((nread=read(fd,buf_r,sizeof(buf_r)))==-1)
              {
                     if(errno==EAGAIN)
                            printf("no data yet\n");
              }
              printf("read %s from FIFO\n",buf_r);
              sleep(1);
       }
       pause();
       unlink(FIFO);
}

//------------------------------------------------------------------------------------------------------------------
//fifo_write.c
//创建有名管道,演示两个不相关的进程之间的通信
//int mkfifo(const char *filename, mode_t mode)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#define FIFO "/home/huang/myfifo"

int main(int argc, char **argv)
{
       int fd;
       char w_buf[100];
       int nwrite;
       if(argc==1)
       {
              printf("please send some message\n");
              exit(1);   
       }
       fd=open(FIFO,O_WRONLY|O_NONBLOCK,0);
       if(fd==-1)
       {
              if(errno==ENXIO)
                     printf("open error;no reading process\n");
              perror("open:");
              return -1;
       }
       memset(w_buf,'a',sizeof(w_buf));
       printf("sizeof(w_buf)=%d\n",sizeof(w_buf));
       while(1)
       {
              if((nwrite=write(fd,w_buf,strlen(w_buf)))==-1)
              {
                     if(errno==EAGAIN)
                            printf("The FIFO has not been write yet.\n");
                     perror("write");
              //     else
                     //     printf("error in writting!\n");
              }
              else
                     printf("write %s to the FIFO\n",w_buf);
              sleep(2);
       }
       close(fd);
}
分享到:
评论

相关推荐

    跨平台进程间通信源码

    在标题中提到的“跨平台进程间通信源码”可能是一个软件库或者框架,旨在帮助开发者在Windows和Linux操作系统上实现进程间的通信。 在Windows系统中,常见的IPC方式包括: 1. **管道(Pipes)**:分为命名管道和...

    windows内存共享进程间通信

    Windows内存共享进程间通信是一种高效的数据交换手段,通过内存映射文件、全局原子等方法实现。然而,正确使用同步机制以避免数据冲突至关重要。了解并熟练掌握各种IPC方式,有助于开发出更稳定、高效的多进程应用...

    通过Windows窗口消息实现 QT进程间通信

    在Windows操作系统环境下,利用Windows窗口消息机制进行进程间通信是一种常见的方法,尤其当涉及到跨语言或者跨框架的交互时。本篇文章将详细探讨如何在QT框架下利用Windows窗口消息来实现进程间通信。 首先,让...

    CEF:进程间通信 Demo(VS2013)

    在这个“CEF:进程间通信 Demo(VS2013)”中,我们将探讨如何在Visual Studio 2013环境下利用CEF实现跨进程通信。 首先,让我们了解什么是进程间通信(IPC,Inter-Process Communication)。在多线程或多进程的...

    进程间通信的6种方式

    开发者需要根据实际需求选择合适的进程间通信手段,例如数据量、实时性、复杂性等因素都会影响决策。在实际应用中,可能还需要结合多线程同步技术,如互斥量、信号量等,来保证数据的安全交换。了解并熟练掌握这些...

    进程间通信

    在单机Windows系统中,进程间通信扮演着至关重要的角色,尤其当需要多进程协作完成一个任务时。本文将深入探讨如何在Windows环境下实现进程间的有效通信,重点讲解内存映射文件这一通信方式。 内存映射文件(Memory...

    利用消息队列实现进程间通信

    本示例中,我们关注的是利用消息队列这一特定的IPC机制,来实现在Linux系统下的进程间通信。消息队列提供了异步通信的能力,使得进程可以在不同时刻发送和接收消息,而无需相互等待。 首先,我们有两个进程,进程A...

    VC利用内存映射实现进程间通信

    在Windows操作系统中,进程间通信...总的来说,VC++中的内存映射提供了一种灵活、高效的进程间通信手段,尤其适用于大量数据的快速传输。通过理解并熟练运用这种技术,开发者可以设计出更加健壮、高效的多进程应用。

    MFC程序通过SendMessage或PostMessage实现进程间通信,实现很简单

    在Windows编程中,进程间通信(Inter-Process Communication, IPC)是一种重要的技术,它允许不同进程之间交换数据和控制信息。MFC(Microsoft Foundation Classes)是微软提供的一个C++库,用于简化Windows应用程序...

    基于管道的进程间通信的小实例

    在这个“基于管道的进程间通信的小实例”中,我们将探讨如何使用管道(pipe)这一特定的IPC机制,以及如何在VC++环境下进行多线程编程。 管道是一种半双工的通信方式,允许数据在一个方向上流动,同时提供一个独立...

    进程间通信_进程间通信_

    进程间通信(IPC,Inter-Process Communication...综上所述,C#提供了丰富的进程间通信手段,开发者可以根据具体应用场景选择合适的方法。在实现过程中,务必注意接收方路径的正确配置,以确保数据能够准确无误地传递。

    进程间通信源码 vc++

    在Windows环境下,VC++(Visual C++)是常用的开发工具,支持多种进程间通信方式。本篇文章将深入探讨使用VC++实现进程间通信的方法,特别是通过广播通信的实现。 首先,我们要理解什么是进程。在操作系统中,进程...

    QT编写的基于内存共享方式的进程间通信

    在QT中,进程间通信(IPC, Inter-Process Communication)是实现不同进程间数据交换的重要手段,尤其在多进程应用程序中显得尤为重要。本项目"QT编写的基于内存共享方式的进程间通信"着重探讨了利用内存共享作为通信...

    进程间通信-管道

    总结起来,命名管道是进程间通信的一种有效手段,尤其适用于同一系统内的进程通信。通过`mkfifo()`、`open()`、`write()`和`read()`等系统调用,我们可以构建起可靠的通信链路。`PipeC.cpp`和`PipeS.cpp`的代码示例...

    利用共享内存及管道实现进程间通信

    在这个场景中,我们将探讨如何利用共享内存和管道这两种机制在Windows环境下,通过VC++6.0进行进程间通信。 **共享内存** 共享内存是一种高效的IPC方式,它允许两个或多个进程直接读写同一块内存区域。在Windows...

    进程间消息通知方式通信

    综上所述,`RegisterWindowMessage`是一种实用的进程间通信手段,它允许开发者创建自定义消息来传递数据和控制信息。然而,实际应用中还需要考虑消息的可靠性和效率,根据具体需求选择合适的通信策略。对于初学者而...

    C++ MFC 进程间通信之邮槽

    综上所述,C++ MFC的邮槽通信是一种有效的进程间通信手段,通过消息队列和消息映射机制,开发者可以方便地在不同进程之间传递数据。理解并熟练掌握这一技术,对于开发复杂的多进程应用具有重要意义。在实际项目中,...

    进程间通信——剪贴板

    进程间通信(IPC,Inter-Process Communication)是操作系统中一种重要的技术,允许不同进程之间共享数据和资源,以实现协同工作。在这个例子中,我们关注的是通过剪贴板这一特殊的共享区域来实现进程间的通信。 ...

Global site tag (gtag.js) - Google Analytics