进程间通信(管道和有名管道)
管道(Pipe)是两个进程之间进行单向通信的机制,因为它的单向性,所以又称为半双工管道。它主要用于进程间的一些简单通信。
- 数据只能由一个进程流向另一个进程(一个写管道,一个读管道);如果要进行全双工通信,需要建立两个管道。
- 管道只能用于父子进程或者兄弟进程之间的通信。
- 管道没有名字,且其缓冲区大小有限。
- 一个进程向管道写数据,数据每次都添加在管道缓冲区的末尾;另一个进程从管道另一端读数据,从缓冲区头部读出数据。
创建管道的命令:
#include <unistd.h> int pipe(int fd[2])
管道两端分别用描述符fd[0]和fd[1]来描述。其中fd[0]只能用于读,称为管道读端;fd[1]只能用于写,称为管道写端。
管道的一般用法:先创建一个管道,之后用fork创建一个子进程,之后父进程关闭管道的读端(或写端),子进程关闭管道的写端(或读端),父进程向管道写输入,子进程就能从管道读数据了。
例子:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> /*读管道*/ void read_from_pipe (int fd) { char message[100]; read (fd,message,100); printf("read from pipe:%s",message); } /*写管道*/ void write_to_pipe (int fd) { char *message = "Hello, pipe!\n"; write (fd, message,strlen(message)+1); } int main(void) { int fd[2]; pid_t pid; int stat_val; if (pipe (fd)) { printf ("create pipe failed!\n"); exit (1); } pid = fork(); switch (pid) { case -1: printf ("fork error!\n"); exit (1); case 0: /*子进程关闭fd1*/ close (fd[1]); read_from_pipe (fd[0]); exit (0); default: /*父进程关闭fd0*/ close (fd[0]); write_to_pipe (fd[1]); wait (&stat_val); exit (0); } return 0; }
有名管道
管道的一个不足之处是没有名字,因此只能在具有亲缘关系的进程之间通信。而“有名管道”与此不同,它提供了一个路径名与之关联,作为一个设备文件存在,即使无亲缘关系的进程之间,只要能访问该路径,也可以通过FIFO进行通信。FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。
函数原型:
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *path,mode_t mode);
path为创建有名管道的路径名;mode为创建有名管道的模式,指明其存取权限。函数调用成功返回0,失败返回-1。
使用一个存在的有名管道之前,需要用open()将其打开。因为有名管道是一个存在于硬盘上的文件,而管道是存在于内存中的特殊文件。
以下程序演示有名管道在无亲缘关系的进程之间如何通信。
写端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "myfifo" #define BUF_SIZE 1024 int main(void) { int fd; char buf[BUF_SIZE] = "Hello procwrite, I come from process named procread!"; umask(0); //指明创建一个有名管道且存取权限为0666,即创建者、与创建者同组的用户、其他用户对该有名管道的访问权限都是可读可写 if (mkfifo (FIFO_NAME, S_IFIFO | 0666) == -1) { perror ("mkfifo error!"); exit (1); } if((fd = open (FIFO_NAME, O_WRONLY) ) == -1)/*以写方式打开FIFO*/ { perror ("fopen error!"); exit (1); } write (fd, buf, strlen(buf)+1); /*向FIFO写数据*/ close (fd); exit (0); }
读端:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/types.h> #define FIFO_NAME "myfifo" #define BUF_SIZE 1024 int main(void) { int fd; char buf[BUF_SIZE]; umask (0); fd = open(FIFO_NAME, O_RDONLY); read (fd, buf, BUF_SIZE); printf ("Read content: %s\n", buf); close (fd); exit (0); }
以上就是管道和有名管道的基本用法了。