管道通信操作

1.管道的打开以及关闭操作

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

int main( void )

{

       int fd[2];                                            /* 管道的文件描述符数组 */

       char str[256];

       if ( (pipe(fd)) < 0 ){

              perror("pipe");

              exit(1);

       }

       write(fd[1],  "create the pipe successfully !\n", 1024 );

                                                                      /*向管道写入端写入数据*/

       read(fd[0], str, sizeof(str) );   /*从管道读出端读出数据*/

       printf ("%s", str );

       printf ( "pipe file descriptors are %d,%d \n", fd[0], fd[1]) ;

       close (fd[0]);                                      /* 关闭管道的读入文件描述符*/

       close (fd[1]);                                      /* 关闭管道的读出文件描述符*/

       return 0;

}

上边这段程序是管道的打开和关闭的实例,首先定义管道的文件描述符数组fd[2],可以理解为管道的两端,分别是读出端fd[0]和写入端fd[1]端。

用函数write()向管道写入端写入数据, write(fd[1], "create the pipe successfully !\n", 1024 ); ,向写入端fd[1]写入"create the pipe successfully !\n"这句话,数字1024是写入的数据的最大长度。

用函数read()从管道读出端读出数据, read(fd[0], str, sizeof(str) ); ,读出管道端的数据,保存在字符串str中。

2.管道在父子进程之间的应用

根据之前学习的进程操作的知识结合管道的知识我们应该能够写出来如何通过管道使父子进程之间进行通信。

第一步,定义基本的东西,比如文件描述符数组、读出数据存放的数组、进程标识符等。

第二步,创建管道。

第三步,创建一个子进程。

第四步,在父进程中向管道写入数据。

第五步,在子进程中从管道读取数据。

第六步,输出子进程中打印的数据。

这六步是父进程向子进程发送数据的流程,是一个框架,具体的程序写入框架中,这个简单的程序就可以写出来了。但是在写代码的过程中还要注意一个问题,先创建一个管道,再创建一个子进程,父进程中有一个管道,子进程中也有一个管道,父进程中写入的内容怎样才能从子进程的管道中读出来?书上有一个父进程写入数据,子进程读出数据的程序。这个程序在应用中,在父进程中将父进程管道的读数据端关闭,然后写入数据,在子进程中将子进程管道的写数据端关闭,然后再读数据。这样就能在父进程中写数据在子进程中读数据。具体代码如下。

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <limits.h>

#include <sys/types.h>

#define BUFSZ PIPE_BUF  /* PIPE_BUF管道默认一次性读写的数据长度*/

int main ( void )

{

       int fd[2];

       char buf[BUFSZ];

       pid_t pid;

       ssize_t len;

       if ( (pipe(fd)) < 0 ){                                    /*创建管道*/

              perror ( "failed to pipe" );

              exit( 1 );

       }

       if ( (pid = fork()) < 0 ){                              /* 创建一个子进程 */

              perror ( "failed to fork " );

              exit( 1 );

       }

       else if ( pid > 0 ){

              close ( fd[0] );                                    /*父进程中关闭管道的读出端*/

              write (fd[1], "hello my son!\n", 14 );    /*父进程向管道写入数据*/

              exit (0);

       }

       else {

              close ( fd[1] );                                    /*子进程关闭管道的写入端*/

              len = read (fd[0], buf, BUFSZ );           /*子进程从管道中读出数据*/

              if ( len < 0 ){

                     perror ( "process failed when read a pipe " );

                     exit( 1 );

              }

              else

                     write(STDOUT_FILENO, buf, len); /*输出到标准输出*/

              exit(0);

       }

}

上边的代码经过调试之后,发现没有问题,那就证明一开始的思路是正确的,可以通过这样的方式使父子进程之间通过管道进行通信。但是,这是关闭了父进程中管道的读出端才将数据发到了子进程中,如果不关闭父进程中管道的读出能不能传过去?然后修改代码发现不关闭管道的读出端也是可以的。

进一步思考,在父进程中写入的数据能不能在父进程和子进程中同时读出来?经过调试代码,在父进程中添加读管道中的数据并显示的代码如下,发现数据只能从父进程中读出来,不能从子进程中读出来。

else if ( pid > 0 ){

              write (fd[1], "hello my son!\n", 14 );    /*父进程向管道写入数据*/

              read(fd[0],buf1,BUFSZ);

printf(“%s\n%s\n”,buf1,buf1);

              exit (0);

       }

这样来看只有两个可能,一种可能就是管道是一次性的,发送接收之后管道就自动清除了。另一种是在父进程的管道写入端写入数据,可以在父进程或子进程的管道读出端读出,但是只能读一次,从父进程中读了之后就不能再在子进程中读,在子进程中读了就不能再在父进程中读。继续修改代码进行调试,先验证第一种可能性。

else if ( pid > 0 ){

              write (fd[1], "hello my son!\n", 14);     /*父进程向管道写入数据*/

              read(fd[0],buf1,BUFSZ);

printf(“%s\n%s\n”,buf1,buf1);

//第二次写入数据

write (fd[1], "hello my son2!\n", 15 );  /*父进程向管道写入数据*/

              read(fd[0],buf1,BUFSZ);

printf(“%s\n%s\n”,buf1,buf1);

              exit (0);

       }

经过调试发现,管道是一直能用的,这样就推翻了第一种假设。那就剩下第二种可能了,关闭父进程中管道的读出端,代码如下,再调试发现,可以只能从子进程中读出数据。

else if ( pid > 0 ){

              close(fd[0]);

              write (fd[1], "hello my son!\n", 14 );    /*父进程向管道写入数据*/

              read(fd[0],buf1,BUFSZ);

printf(“%s\n%s\n”,buf1,buf1);

              exit (0);

       }

从这一系列的调试过程可以理解管道的工作过程,了解管道在父子进程之间进行通信的过程。

                               

上图中第一幅图是创建管道和子进程之后的管道示意图,但是在通信的时候只能从左边选一根写入的线,在右边选一根读出的线。用的比较多的就是图2中在父进程中通过管道发送数据到子进程中。

3.管道在兄弟进程之间的应用

管道在父子进程之间的应用明白之后,在兄弟之间的应用就很好理解了。

第一步,定义基本的东西,比如文件描述符数组、读出数据存放的数组、进程标识符等。

第二步,创建管道。

第三步,创建第一个子进程。

第四步,在第一个子进程中向管道中写入数据。

第五步,创建第二个子进程

第六步,在第二个子进程中读取管道中的数据。

第七步,输出第二个子进程中打印的数据。

具体代码如下所示:

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <limits.h>

#include <fcntl.h>

#include <sys/types.h>

#define BUFSZ PIPE_BUF

void err_quit(char * msg){

       perror( msg );

       exit(1);

}

int main ( void )

{

       int fd[2];

       char buf[BUFSZ];          /* 缓冲区 */

       pid_t pid;

       int len;

       if ( (pipe(fd)) < 0 )  /*创建管道*/

              err_quit( "pipe" );

       if ( (pid = fork()) < 0 )                               /*创建第一个子进程*/

              err_quit("fork");

       else if ( pid == 0 ){                                   /*子进程中*/

              close ( fd[0] );                                    /*关闭不使用的文件描述符*/

              write(fd[1], "hello brother!\n", 15 );     /*发送消息*/

              exit(0);

       }

       if ( (pid = fork()) < 0 )                               /*创建第二个子进程*/

              err_quit("fork");

       else if ( pid > 0 ){                                      /*父进程中*/

              close ( fd[0] );

              close ( fd[1] );

              exit ( 0 );

       }

       else {                                                                     /*子进程中*/

              close ( fd[1] );                                    /*关闭不使用的文件描述符*/

              len = read (fd[0], buf, BUFSZ );           /*读取消息*/

              write(STDOUT_FILENO, buf, len);

              exit(0);

       }

}
时间: 2024-10-12 16:15:10

管道通信操作的相关文章

14.有名管道通信

有名管道: 有名管道又称为FIFO文件,因此我们对有名管道的操作可以采用操作文件的方法,如使用 open,read,write等. 有名管道的学习: ? 有名管道与其他文件的对比: FIFO文件在使用上和普通文件有相似之处,但是也有不同之处: 1. 读取Fifo文件的进程只能以"RDONLY"方式打开fifo文件. 2. 写Fifo文件的进程只能以"WRONLY"方式打开fifo文件. 3. Fifo文件里面的内容被读取后,就消失了.但是普通文件里面的内容读取后还存

管道通信之无名管道---pipe()

pipe()函数在子进程产生之前就应该存在. 父子进程之间只进行一次传递 1 /*============================================ 2 > Copyright (C) 2014 All rights reserved. 3 > FileName:onepipe.c 4 > author:donald 5 > details: 6 ==============================================*/ 7 #inclu

管道通信,王明学learn

管道通信 一.通讯目的 1.数据传输 一个进程需要将数据发送给另一个进程. 2.资源共享 多个进程之间共享同样的资源. 3.通知事件 一个进程需要向另一个/组进程发送消息,通知它们发生了某事件. 4.进程控制 有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变. 二.通讯发展 Linux进程间通信(IPC:interprocesscommunication)由以下几部分发展而来: 1.UNIX进程间通信 2.基于Sy

fork产生子进程利用pipe管道通信

http://siqun.blog.163.com/blog/static/213496001201341231121720/ 转载链接:http://hi.baidu.com/hj11yc/item/9a2ea30cca773077bfe97efc注:加了一点内容 进程间通信 fork pipe pie_t 等用法(管道机制 通信) 每个进程各自有不同的用户地址空间,任 何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲 区,进程1把数据从用户

无名管道通信

一.核心理论 1.进程通信方式(IPC) (1).通讯的目的: 数据传输,资源共享,通知事件,进程控制 (2).通讯的发展:UNIX进程间的通信.基于System V进程间的通信.POSIX进程间通信 (3).通信方式 : 无名管道(pipe),有名管道(FIFO),信号(signal), 消息队列, 共享内存, 信号量, 套接字(socket) 2.管道通信方式(特点) (1).管道通讯是单向的,有固定的读端和写端 (2).数据被进程从管道读出后,在管道中该数据就不存在了 (3).当进程去读取

linux 管道通信

进程通信 进程是系统分配资源的最小单位, 不同进程之间是相互隔离的, Linux常用于进程通信的几种方式有 匿名管道及有名管道 : 匿名管道用于具有亲缘关系的进程通信, 有名管道则可用于一般进程之间. 信号 : 软件层对中断机制的一种模拟. 消息队列 共享内存 : 不同进程享同一块内存区域, 不同进程可以实时查看对方对共享内存的更新. 需要借助同步机制, 如互斥锁, 信号量. 信号量 : 主要用于不同进程以及同一进程不同线程的同步和互斥. 套接字 : 广泛用于网络间进程通信. 无名管道 管道是是

Linux学习记录--命名管道通信

命名管道通信 什么是命名管道 一个主要的限制是,它是匿名管道的应用还没有名字,因此,只有它可以用于进程间通信的方式与亲缘关系.在命名管道(named pipe或FIFO)提出后,该限制得到了克服.FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中. 这样,即使与FIFO的创建进程不存在亲缘关系的进程,仅仅要可以訪问该路径,就行彼此通过FIFO相互通信 有名管道创建 int mkfifo(const char * pathname, mode_t mode)

进程的通信:共享存储、消息传递和管道通信

进程通信是指进程之间的信息交换.PV操作是低级通信方式,高级通信方式是指以较高的效率传输大量数据的通信方式.高级通信方法主要有以下三个类. 共享存储 在通信的进程之间存在一块可直接访问的共享空间,通过对这片共享空间进行写/读操作实现进程之间的信息交换.在对共享空间进行写/读操作时,需要使用同步互斥工具(如P操作.V操作),对共享空间的写/读进行控制.共享存储又分为两种:低级方式的共享是基于数据结构的共享:高级方式则是基于存储区的共享.操作系统只负责为通信进程提供可共享使用的存储空间和同步互斥工具

go语言快速入门 IPC之管道通信 8

熟悉Unix/C编程的应该对IPC也非常的熟悉,多进程之间的通信主要的手段有管道/信号量/共享内存/Socket等,而管道作为父子进程间进行少量数据传递的有效手段也得到了广泛的应用,在这篇文章中我们来看一下go语言中如何使用管道进行进程进行通信. 管道的使用 在linux下,管道被非常广泛地使用,一般在编程中我们实现了popen等的应用即可提供管道功能.而在命令行中使用地也非常多,|就是最为典型的管道的应用例子.shell会为|符号两侧的命令各创建一个脚本,将左侧的输出管道与右侧的输入管道进行连