您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 《LinuxC从入门到精通》明日科技第08章进程间通信
进程间通信概述本讲大纲:进程间通信的工作原理进程间通信的主要分类进程间通信的工作原理进程间通信(Inter-ProcessCommunication,IPC)是指在两个或者多个不同的进程间传递或者交换信息,通过信息的传递建立几个进程间的联系,协调一个系统中的多的进程之间的行为。8.1.1进程间通信的工作原理进程与进程之间是相互独立的,各自运行在自己的虚拟内存中,要想在进程与进程之间建立联系,需要通过内核,在内核中开辟一块缓冲区,两个进程的信息在缓冲区中进行交换或者传递。进程间通信原理如图8.1所示。进程A进程B内核图8.1进程间通信工作原理进程间通信的工作原理是进程A中的数据写入到内核中,进程B中的数据也写入到内核中,两者在内核中进行交换,交换过后,进程A读取内核中的数据,进程B也读取内核中的数据,这样两个进程间交换数据的通信就完成了。两个进程通过内核建立了联系,那么交换数据、传递数据、发送事件等行为就都可以实现了。进程间通信的主要分类在Linux系统中,常见的进程间通信主要包括管道通信、共享内存通信、信号量通信、消息队列通信、套接口(SOCKET)通信和全双工管道通信。Linux系统除了支持信号和管道外,还支持SYSV(SystemV)子系统中的进程间通信机制。在SYSV的IPC机制中,包括共享内存、信号量和消息队列通信。标题管道与命名管道本讲大纲:管道基本定义管道创建和管道关闭pipe函数实现管道通信命名管道基本定义在Shell中创建命名管道mkfifo函数创建命名管道管道基本定义管道与命名管道是最基本的IPC机制之一,管道主要用于父子或者兄弟进程间的数据读写,命名管道则可以在无关联的进程间进行沟通传递数据。在这一节中,主要讲解管道通信和命名管道通信这两种通信方式的工作原理,以及两种通信方式的实际应用情况。8.2.1管道基本定义所谓的管道,就像生活中的煤气管道、下水管道等传输气体和液体的工具,而在进程通信意义上的管道就是传输信息或数据的工具。以下水管道为例,当从管道一段输送水流到另一端时,只有一个传输方向,不可能同时出现两个传输方向。在Linux系统中的进程间通信中管道这个概念也是如此,某一时刻只能单一方向传递数据,不能双向传递数据,这种工作模式就叫做单双工模式。单双工工作模式的管道通信是只能从一段写数据,另一端读取数据。说明:全双工的工作模式是指管道一段发送数据的同时还可以接收数据,而接收数据的一端也可以读取数据。在某些版本的Unix系统中,管道是支持全双工工作模式的。但是在本书中介绍的Linux系统中,管道是只支持单双工工作模式的。管道创建和管道关闭管道由Linux系统提供的pipe()函数创建,该函数的原型为:#includeunistd.hintpipe(intfiledes[2]);pipe()函数用于在内核中创建一个管道,该管道一端用于读取管道中的数据,另一端用于将数据写入到管道中。在创建一个管道之后,会获得一对文件描述符,用于读取和写入。然后将参数数组filedes中的两个值,传递给获取到的两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端。pipe()函数调用成功,返回值为0;否则返回-1,并且设置了适当的错误返回信息,返回信息如下:EFAULT:参数filedes非法。EMFILE:进程中使用了过多的文件描述。ENFILE:打开的文件达到了系统允许的最大值。pipe()函数只是创建了管道,要想从管道中读取数据或者向管道中写入数据,需要使用read()函数和write()函数从管道进行读写操作。当管道通信结束后,需要使用close()函数关闭管道的两端,即读端和写端。说明:read()函数和write()函数的相关讲解,请参照第9章文件操作中关于这两个函数的介绍。pipe函数实现管道通信调用pipe()函数实现创建两个进程间的管道通信,pipe()函数只允许两个有联系的进程进行通信,如父子进程或者兄弟进程,因此首先需要使用fork函数创建一个或者两个新的进程,然后再父子或兄弟进程之间进行数据的传递。在前面介绍管道时,已经提到在Linux系统中管道是半双工模式的通信,即使用管道通信只能进行单向传递,也就是管道总共有两端,一端只能用于写入数据,其文件描述符为filedes[1];另一端则只能用于读取数据,其文件描述符为filedes[0]。下面通过一个实例讲解管道的单向通信是如何实现的。例8.1在Linux系统中,调用pipe()函数创建一个管道,实现管道的单向通信。(实例位置:光盘\TM\sl\8\1)(1)在父进程中调用pipe()函数创建一个管道,产生一个文件描述符filedes[0]指向管道的读端和一个文件描述符filedes[1]指向管道的写端。(2)在父进程中调用一个fork()函数创建一个一摸一样的新进程,也就是所谓的子进程。父进程的文件描述符一个指向管道读端,另一个指向管道的写端,同样,子进程也如此。(3)在父进程关闭指向管道写端的文件描述符filedes[1],在子进程中,关闭指向管道读端的文件描述符filedes[0],此时,就可以将父进程中的某个数据写入管道,然后再子进程中,将此数据读取出来。(4)这样一个简单的单向通信就实现了。上述实现单向通信的过程如图8.2所示。图8.2单向通信的实现过程在了解了单向通信的实现过程后,可以轻松的使用代码实现此功能,实现代码如下:#includeunistd.h#includestdio.h#includestring.h#defineMAXSIZE100intmain(void){intfd[2],pid,line;charmessage[MAXSIZE];/*创建管道*/if(pipe(fd)==-1){perror(createpipefailed!);调用pipe()函数实现创建两个进程间的管道通信,pipe()函数只允许两个有联系的进程进行通信,如父子进程或者兄弟进程,因此首先需要使用fork函数创建一个或者两个新的进程,然后再父子或兄弟进程之间进行数据的传递。在前面介绍管道时,已经提到在Linux系统中管道是半双工模式的通信,即使用管道通信只能进行单向传递,也就是管道总共有两端,一端只能用于写入数据,其文件描述符为filedes[1];另一端则只能用于读取数据,其文件描述符为filedes[0]。下面通过一个实例讲解管道的单向通信是如何实现的。例8.1在Linux系统中,调用pipe()函数创建一个管道,实现管道的单向通信。(实例位置:光盘\TM\sl\8\1)(1)在父进程中调用pipe()函数创建一个管道,产生一个文件描述符filedes[0]指向管道的读端和一个文件描述符filedes[1]指向管道的写端。(2)在父进程中调用一个fork()函数创建一个一摸一样的新进程,也就是所谓的子进程。父进程的文件描述符一个指向管道读端,另一个指向管道的写端,同样,子进程也如此。(3)在父进程关闭指向管道写端的文件描述符filedes[1],在子进程中,关闭指向管道读端的文件描述符filedes[0],此时,就可以将父进程中的某个数据写入管道,然后再子进程中,将此数据读取出来。(4)这样一个简单的单向通信就实现了。上述实现单向通信的过程如图8.2所示。图8.2单向通信的实现过程在了解了单向通信的实现过程后,可以轻松的使用代码实现此功能,实现代码如下:#includeunistd.h#includestdio.h#includestring.h#defineMAXSIZE100intmain(void){intfd[2],pid,line;charmessage[MAXSIZE];/*创建管道*/if(pipe(fd)==-1){perror(createpipefailed!);调用pipe()函数实现创建两个进程间的管道通信,pipe()函数只允许两个有联系的进程进行通信,如父子进程或者兄弟进程,因此首先需要使用fork函数创建一个或者两个新的进程,然后再父子或兄弟进程之间进行数据的传递。在前面介绍管道时,已经提到在Linux系统中管道是半双工模式的通信,即使用管道通信只能进行单向传递,也就是管道总共有两端,一端只能用于写入数据,其文件描述符为filedes[1];另一端则只能用于读取数据,其文件描述符为filedes[0]。下面通过一个实例讲解管道的单向通信是如何实现的。例8.1在Linux系统中,调用pipe()函数创建一个管道,实现管道的单向通信。(实例位置:光盘\TM\sl\8\1)(1)在父进程中调用pipe()函数创建一个管道,产生一个文件描述符filedes[0]指向管道的读端和一个文件描述符filedes[1]指向管道的写端。(2)在父进程中调用一个fork()函数创建一个一摸一样的新进程,也就是所谓的子进程。父进程的文件描述符一个指向管道读端,另一个指向管道的写端,同样,子进程也如此。(3)在父进程关闭指向管道写端的文件描述符filedes[1],在子进程中,关闭指向管道读端的文件描述符filedes[0],此时,就可以将父进程中的某个数据写入管道,然后再子进程中,将此数据读取出来。(4)这样一个简单的单向通信就实现了。上述实现单向通信的过程如图8.2所示。图8.2单向通信的实现过程在了解了单向通信的实现过程后,可以轻松的使用代码实现此功能,实现代码如下:#includeunistd.h#includestdio.h#includestring.h#defineMAXSIZE100intmain(void){intfd[2],pid,line;charmessage[MAXSIZE];/*创建管道*/if(pipe(fd)==-1){perror(createpipefailed!);pipe函数实现管道通信父进程filedes[0]filedes[1]读端写端父进程filedes[0]filedes[1]读端写端子进程filedes[0]filedes[1]父进程filedes[0]filedes[1]读端写端子进程filedes[0]filedes[1](1)创建管道(2)创建子进程(3)实现单向通信命名管道基本定义在前面介绍的使用管道进行进程间通信的方法受到很多的限制,受限制之一就是两个进程进行通信,必须是两个相关联的进程,如父子进程或者兄弟进程等。那么没有关系的进程之间有时候也需要进行通信,该如何解决呢?命名管道解决了这个问题。命名管道,通常被称之为FIFO(first-in,first-out),由FIFO可以知道,命名管道遵循先进先出的原则。命名管道作为特殊的设备文件存在于文件系统中,因此,在进程中可以使用open()函数和close()函数打开和关闭命名管道。命名管道与管道类似,两者的区别在于命名管道提供了一个路径名,该路径名以特殊的设备文件的形式存放在文件系统中。因此两个进程间可以没有关系,通过访问该路径来建立联系,进行两个进程间的数据交换。但管道与命名管道都遵循先进先出的原则,也就是指最先写入的数据添加在结尾位置,读取数据时,从开始处返回数据。创建一个命名管道有两种方法,一种是通过函数创建命名管道,另一种是在终端中输入命令创建命名管道,接下来对这两种方法的应用进行讲解。在Shell中创建命名管道在Shell中输入mknod命令和mkfifo命令可以创建一个命名管道。在终端中输入命令“mknod--help”,可以查看这个命令的用法等信息。效果如图8.4所示。通过突8.4的介绍,使用mknod创建一个命名管道文件,可以使用命令“mknod路径名称p”,参数p是指创建一个命名管道文件,如图8.5所示。在Linux系统中,还有一个mkfifo命令,也可以创建一个命名管道文件,该命令在终端中的详细介绍如图8.6所示。在图8.6中讲解了mkfifo命令的使用方法,可以发现这个命令比mknod命令更简单,直接写出创建命名管道文
本文标题:《LinuxC从入门到精通》明日科技第08章进程间通信
链接地址:https://www.777doc.com/doc-2836001 .html