1. 何为管道
我的理解就是管道是一个类似于队列的缓冲区,数据先进先出。一个进程发送数据,一个进程接受数据
2. 管道分类
2.1 无名管道
无名管道适用于有亲缘关系的进程,如父子进程。因为子进程的内存空间是直接拷贝的父进程的内存空间,所以父进程创建管道后得到的文件描述符也被拷贝了一份,而其他没有亲缘关系的进程则无法的到该文件描述符(没有文件名与之对应)。
创建无名管道的接口:
#include <unistd.h>
int pipe(int pipefd[2]);
例子:
#include<stdio.h>
#include<unistd.h>
/* 父进程生成数据, 子进程取出数据并打印 */
int main(void)
{
int fd[2];
int ret = 0;
int data = 0;
ret = pipe(fd);
if (ret < 0) {
perror("pipe error");
return -1;
}
ret = fork();
if (ret == 0) { // 子进程
while(1) {
ret = read(fd[0], &data, sizeof(data));
if (ret < 0) {
printf("read error");
return -1;
}
printf("data: %d\n", data);
}
}
else { // 父进程
while(1) {
data += 1;
write(fd[1], &data, sizeof(data));
sleep(1); // 一秒钟产生一个数据
}
}
close(fd[0]);
close(fd[1]);
return 0;
}
2.2 有名管道
有名管道在没有亲缘关系的进程之间也能够使用,顾名思义,有名管道就是给管道命一个名字,也就是创建了一个文件,该文件称为管道文件。与普通文件不同的是,管道文件的数据是先进先出的,每个数据只能取一次,取了就没了,并且不能够使用lseek函数改变偏移量。
需要注意:
- 管道建立好后,在打开管道文件的时候,管道的两端读写必须分别打开,有任何一方未打开,则在调用open的时候就阻塞。比如,一个进程以写的方式打开管道文件,但没有任何进程以读的方式打开,那么就会阻塞在open函数,直到某个进程取以读的方式打开管道文件
- 管道大小是有最大值的,可以使用宏PIPE_BUF(limits.h)查看。
- 管道默认是阻塞的,在没有数据可读的时候,读操作会阻塞。
例子:
read_pipe.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#define FIFO_NAME "./fifo_test"
/* 读取管道内的数据并打印, 每两秒读取一次 */
int main(void)
{
int ret = 0;
int fifo_fd;
int data = 0;
// 打开管道
fifo_fd = open(FIFO_NAME, O_RDONLY);
if (fifo_fd < 0) {
perror("open fifo error");
return -1;
}
printf("[read] open ok\n");
while(1) {
// 读取数据
ret = read(fifo_fd, &data, sizeof(data));
if (ret < 0) {
perror("read error");
return -1;
}
printf("data: %d\n", data);
sleep(2);
}
close(fifo_fd);
return 0;
}
write_pipe.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#define FIFO_NAME "./fifo_test"
/* 创建管道, 向管道内写入数据,每一秒写入一次 */
int main(void)
{
int ret = 0;
int fifo_fd;
//char *data = "hello World";
int data = 0;
// 没有就创建
if (access(FIFO_NAME, F_OK) == -1) {
ret = mkfifo(FIFO_NAME, 0777);
if (ret < 0) {
perror("mkfifo error\n");
return -1;
}
}
// 打开管道
fifo_fd = open(FIFO_NAME, O_WRONLY);
if (fifo_fd < 0) {
perror("open fifo error");
return -1;
}
printf("[write] open ok\n");
while(1) {
// 写入数据
data += 1;
write(fifo_fd, &data, sizeof(data));
sleep(1);
}
close(fifo_fd);
return 0;
}