LINUX_C编程实战-第十章《进程间通信》-管道

来源:互联网 发布:五金行业erp软件报价 编辑:程序博客网 时间:2024/06/04 19:02

一、进程间的通信(IPC)-管道

管道分为无名管道(pipe),有名管道(FIFO)二种;

区别:无名管道是存在于内存的特殊文件,而有名管道是一个存在硬盘上的文件

无名管道的概念:管道是由内核管理的一个缓冲区,相当于放入内存的一个纸条。管道的一端连接一个进程的输出,这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失

无名管道特点:1、半双工(单向通信)机制,数据只能有一个进程流入下一个进程(一个写管道,一个读管道);全双工通信需要创建两个管道;

                        2、数据只能在具有血缘关系的进程间通信;

                        3、管道没有名字,缓冲区大小一定(被分配一个页面作为缓冲区),是一种特殊的文件—PIPE_BUF;

无名管道的创建与打开:定义头文件 #include<unistd.h>

                                      int pipe(int fd[2]); 成功返回0,数组中包含两个文件描述符,失败返回-1;

                                      fd[0](管道读端) & fd[1](管道写端)用于描述管道的两端,读端只能读,写端只能写;可以用操作I/O文件的方式操作管道;

无名管道的读写:读端在读取数据时应该及时关闭不需要的管道的另一端(写端);写端亦如此

                          ps:必须再fork之前调用pipe函数创建管道,否则子进程无法继承管道的描述符

代码功能如下:主进程通过命令行向管道写入数据,子进程从标准输入里面读出该参数;将读端重定向到标准输入端

/* pipe.c文件*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>int main( int argc,char **argv){pid_t pid;int fd[2];int stat_val;if(pipe(fd)){printf("creat pipe failed\n");exit(1);}pid = fork();switch(pid){case 0:sleep(5);close(fd[1]);close(0);dup(fd[0]);//dup2(fd[0],0);execve("ctrlprocess",(void *)argv,NULL);exit(0);case -1:printf("fork failed\n");exit(0);default:close(fd[0]);write(fd[1],argv[1],strlen(argv[1]));close(fd[1]);wait(&stat_val);break;}return 0;}

可执行的代码:

/*ctrlprocess.c*/#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<stdlib.h>#include<stdio.h>int main(int argc,char **argv){printf("I am here\n");char message[100];int n;while(1){n=read(0,message,90);printf("n= %d\n",n);if(n>0){printf("message= %s\n",message);}exit(0);}}
程序执行如下:



有名管道(named pipe 或pipe)

特点:可以在非亲属关系中进行通信;以FIFO的文件形式存在文件系统中,是一个设备文件,相当于创建了一个文件,只要具有读写权限就可以访问 

创建的方式二种:第一种,shell命令,mknod(mkfifo) 路径名>                                       

第二种,系统函数:int mkfifo(const char *pathname,mode_t mode);//S_IFFO | 0666,表明文件存取权限                                     

                             int mknod(const char *pathname,mode_t mode,dev_t dev);
                                  成功返回0,失败返回-1;

注意:使用FIFO时要先使用open()函数将其打开;调用open打开有名管道的进程会阻塞,但如果以O_RDWR打开,一定不会阻塞;以O_RDONLY打开,则调用open的进程将会被阻塞直到有写方打开有名管道;以O_WRONLY打开,则调用open的进程也会被阻塞直到有读方打开有名管道;

/*writepipe.c*/#include<stdio.h>#include<stdlib.h>#include<sys/stat.h>#include<sys/types.h>#include<fcntl.h>#include<unistd.h>#define NAMEDPIPE  "/home/czg/file/pipe"int main(char argc,char *argv[]){int fd,n;if(argc < 2)printf("input data\n");/* 非堵塞,只读的形式打开文件*/fd = open(NAMEDPIPE,O_WRONLY );if(fd<0){perror("open failed");}printf("fd = %d\n",fd);if(fd < 0)printf("open failed\n");n=write(fd,argv[1],3);printf("n=%d\n",n);close(fd);return 0;}

/* readpipe.c*/#include<stdio.h>#include<stdlib.h>#include<sys/stat.h>#include<sys/types.h>#include<fcntl.h>#include<unistd.h>#include<string.h>#include<unistd.h>#define NAMEDPIPE  "/home/czg/file/pipe"int main(int argc,char **argv){int fd,n;char buf[200];memset(buf,0,sizeof(buf));/* 确认管道文件是否存在,有则删除*/if(access(NAMEDPIPE,F_OK)==0){printf("into access\n");execlp("rm","-f",NAMEDPIPE,NULL);}/* 创建管道,使其克读写执行*/if(mkfifo(NAMEDPIPE,0777) != 0){printf("mkfifo error\n");}/* 只读方式open管道时,进程被阻塞,至到有写方可打开管道,亦可加O_NONBLOCK(无堵塞)*/fd = open(NAMEDPIPE,O_RDONLY );printf("fd = %d\n",fd);sleep(5);while(1){memset(buf,0,sizeof(buf));n=read(fd,buf,2);if(n==-1)perror("read error");else if(n==0)printf("no data\n");else{printf("get data:%s\nn=%d\n",buf,n);sleep(2);}}close(fd);return 0;}

代码结果:


原创粉丝点击