管道(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);
}
以上就是管道和有名管道的基本用法了。