深刻理解Linux进程间通信

上传人:jiups****uk12 文档编号:40020523 上传时间:2018-05-22 格式:DOC 页数:70 大小:574KB
返回 下载 相关 举报
深刻理解Linux进程间通信_第1页
第1页 / 共70页
深刻理解Linux进程间通信_第2页
第2页 / 共70页
深刻理解Linux进程间通信_第3页
第3页 / 共70页
深刻理解Linux进程间通信_第4页
第4页 / 共70页
深刻理解Linux进程间通信_第5页
第5页 / 共70页
点击查看更多>>
资源描述

《深刻理解Linux进程间通信》由会员分享,可在线阅读,更多相关《深刻理解Linux进程间通信(70页珍藏版)》请在金锄头文库上搜索。

1、深刻理解 Linux 进程间通信(IPC)级别: 初级郑彦兴 ()国防科大计算机学院 2002 年 12 月 11 日 一个大型的应用系统,往往需要众多进程协作,进程(Linux 进程概念见附 1) 间通信的重要性显而易见。本系列文章阐述了 Linux 环境下的几种主要进程间 通信手段,并针对每个通信手段关键技术环节给出详细实例。为达到阐明问题 的目的,本文还对某些通信手段的内部实现机制进行了分析。 序序 linux 下的进程通信手段基本上是从 Unix 平台上的进程通信手段继承而来的。 而对 Unix 发展做出重大贡献的两大主力 AT参数 int fd2为一个长度为 2 的文件描述符数组,f

2、d0是读出端,fd1是写入端,函数的返回值为 0 表示成功,-1 表示失败。当函数成功返回,则自动维护了一个从 fd1到fd0的数据通道。下面实例演示了如何使用 pipe 函数创建管道以及关闭管道。程序中先使用函数 pipe 建立管道,并使用管道传输数据,在程序的结束部分,释放掉管道占用的文件资源(两个文件描述符),具体实现如下。(1)在)在 vi 编辑器中编辑以下程序:编辑器中编辑以下程序:程序清单 14-1 opro_pipe.c 管道的打开以及关闭操作#include #include #include int main( void )int fd2; /* 管道的文件描述符数组 */c

3、har str256;if ( (pipe(fd) #include #include #include #define BUFES PIPE_BUF /* PIPE_BUF 管道默认一次性读写的数据长度*/int main ( void ) int fd2;char bufBUFSZ;pid_t pid;int len;if ( (pipe(fd) 0 )close ( fd0 ); /*父进程中关闭管道的读出端*/write (fd1, “hello my son!n“, 14 ); /*父进程向管道写入数据*/exit ( 0);else close ( fd1 ); /*子进程关闭管道

4、的写入端*/len = read (fd0, buf, BUFS ); /*子进程从管道中读出数据*/if ( len #include #include #include #include #define BUFES PIPE_BUFvoid err_quit(char * msg)perror( msg );exit(1);int main ( void ) int fd2;char bufBUFSZ; /* 缓冲区 */pid_t pid;int len;if ( (pipe(fd) 0 ) /*父进程中*/close ( fd0 );close ( fd1 );exit ( 0 );e

5、lse /*子进程中*/close ( fd1 ); /*关闭不使用的文件描述符*/len = read (fd0, buf, BUFS ); /*读取消息*/write(STDOUT_FILENO, buf, len);exit(0);(2)在 shell 中编译该程序如下:$gcc bro_bro.c-o bro_bro(3)在 shell 中运行该程序如下:$./ bro_brohello brother!上述程序中父进程分别建立了 2 个子进程,在子进程 1 中关闭了管道的读出端,在子进程 2 中关闭了管道的输入端,并在父进程中关闭了管道的两端。注意:程序中父进程在创建第 1 个子进程

6、时并没有关闭管道两端,而是在创建第 2 个进程时才关闭管道。这是为了在创建第 2 个进程时,子进程可以继承存活的管道,而不是一个两端已经关闭的管道。14.2.4 创建管道的标准库函数创建管道的标准库函数从程序 14-2 和程序 14-3 中可以总结出管道操作的一个流程。父进程中先使用 pipe 函数创建管道,在调用 fork 函数创建子进程,在父子进程中维护管道的数据流向。程序退出时及时关闭管道的两端,具体流程如图 14-4 所示。(点击查看大图)图 14-4 匿名管道的创建流程管道操作的基本流程为:先创建一个管道,使用 fork 创建子进程, 在父子进程中关闭不需要的文件描述符使用管道通信,

7、程序结束。由于这是一个比较规范也是比较常用的管道使用模式,所以在 ANSI/ISO C 中将以上操作定义在两个标准的库函数 popen 和 pclose 中,它们的函数原型是: #include FILE *popen( const char * command, const char *mode );int pclose ( FILE *stream );函数 popen 的参数 command 是一个在 shell 中可运行的命令字符串的指针,参数mode 是一个字符指针,这个参数只有两种值可以使用,r 或者 w,分别表示 popen 函数的返回值是一个读打开文件指针,还是写打开文件指针。

8、当函数失败时返回值为 NULL,并设置出错变量 errno。popen 函数先执行创建一个管道,然后调用 fork 函数创建子进程,紧接着执行一个exec 函数调用, 调用/bin/sh -c 来执行参数 command 中的命令字符串,然后函数返回一个标准的 I/O 文件指针。返回的文件指针类型与参数 mode 有关,如果参数 mode 是 r 则文件指针连接到 command 命令的标准输出,如果是 w 则文件指针连接到 command 命令的标准输 入。为了关闭 popen 函数返回的文件指针,可以调用 pclose 函数。pclose 函数的参数 stream 是一个 popen 打开

9、的文件描述符,当函数失败返回-1。下面实例演示了使用 popen 和 pclose 函数实现调用 shell 命令 cat 来打印一个文件到显示器的程序。程序中先使用 popen 函数为 cat 命令创建一条数据管道,并指定数据管道从cat 命令的输出读出数据。在后续的代码中使用 fgets 函数读出数据,并将数据显示到标准输出中。(1)在)在 vi 编辑器中编辑该程序如下:编辑器中编辑该程序如下:程序清单 14-4 recat.c 使用 popen 和 pclose 函数创建管道#include #include #include #include #include #define BUFE

10、S PIPE_BUFint main ( void )FILE *fp;char * cmd = “cat file1“; /*shell 命令*/char * bufBUFSZ;if (fp = popen( cmd , “r“)=NULL ) /*创建子进程到父进程的数据管道*/perror ( “ failed to popen “ ) ;exit ( 1 ) ;while (fgets(buf, BUFSZ, fp)!= NULL ) /*读出管道的数据*/printf ( “%s“, buf ); pclose ( fp ) ; /*关闭管道*/exit (0) ;(2)在 shel

11、l 中编译该程序如下:$gcc recat.c-o recat(3)在 shell 中运行该程序如下:$./ recatUsed the popen and pclose function to create a pipe !说明:在程序 14-4 recat.c 中,使用 popen 和 pclose 函数创建管道并关闭管道,使用gets 函数从管道输出端读取数据并打印到标准输出中,使用 popen 和 pclose 可以更简洁地控制管道,而无需那些繁杂的代码。当然这样做的结果是降低了程序员对管道的控制能力。例如,popen 函数返回的是文件指针,所以,在管道读写时就不能使用低级的 read

12、 和write I/O 调用了,只能使用基于文件指针的 I/O 函数,并且在 popen 函数中调用 exec 函数来复写子进程,这也是要花费一段运行时间的。14.3 FIFO 管道管道FIFO 也称为有名管道,它是一种文件类型,在文件系统中可以看到。程序中可以查看文件 stat 结构中 st_mode 成员的值来判断文件是否是 FIFO 文件。创建一个 FIFO 文件类似于创建文件,FIFO 文件就像普通文件一样。本小节将介绍 FIFO 管道。14.3.1 FIFO 的概念的概念在本章 14.2.2 小节详细说明了匿名管道的缺点以及限制条件,在 FIFO 中可以很好地解决在无关进程间数据交换

13、的要求,并且由于它们是存在于文件系统中的,这也提供了一种比匿名管道更持久稳定的通信办法。FIFO 的通信方式类似于在进程中使用文件来传输数据,只不过 FIFO 类型文件同时具有管道的特性。在数据读出时,FIFO 管道中同时清除数据。在 shell 中 mkfifo 命令可以建立有名管道,下面通过一个实例来帮助读者理解 FIFO。mkfifo 命令的帮助手册如下所示:mkfifo option name.其中 option 选项中可以选择要创建 FIFO 的模式,使用形式为-m mode,这里 mode 指出将要创建 FIFO 的八进制模式,注意,这里新创建的 FIFO 会像普通文件一样受到创建

14、进程的umask 修正。在 shell 中输入命令如下:$mkfifo -m 600 fifocat$cat fifocat$./recat fifocat#include #include #include #include #include #define BUFES PIPE_BUFint main ( void )FILE *fp;char * cmd = “cat file1“; /*shell 命令*/char * bufBUFSZ;.pclose ( fp ) ; /*关闭管道*/exit (0) ;$_以上实例使用系统命令 mkfifo 创建 FIFO 类型文件 fifocat

15、,并通过 14.2.4 节的程序 recat 来 读取文件 recat.c,将程序的标准输出从定向到 fifocat 中,再使用命令 cat 从 fifocat 读出数 据。14.3.2 创建创建 FIFO创建一个 FIFO 文件类似于创建文件,FIFO 文件就像普通文件一样,也是可以经过路径名来访问的。相应文件 stat 结构的域 st_mode 的编码指明了文件是否是 FIFO 类型。FIFO 管道通过函数 mkfifo 创建,函数原型如下:#include #include int mkfifo( const char * filename, mode_t mode );mkfifo 函

16、数中参数 mode 指定 FIFO 的读写权限,新创建 FIFO 的用户 ID 和组 ID 规则域 open 函数相同。参数 filename 指定新创建 FIFO 的文件名称。函数如果成功返回 0,出错返回-1,并更改 errno 的值。errno 有可能出现的值为:EACCESS、EEXIST、ENAMETOO- LONG、ENOENT、ENOSPE、ENOTDIR 和EROFS。下面实例演示了如何使用 mkfifo 函数来创建一个 FIFO。程序中从程序的命令行参数中得到一个文件名,然后使用 mkfifo 函数创建 FIFO 文件。新创建的 FIFO 只具有读写权限。由于 FIFO 文件的特性,所以它被隐性地规定不具有执行权限。(

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 中学教育 > 其它中学文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号