1.无名管道
1.1特点
(1)只能用于具有亲缘关系的进程之间的通信
(2)半双工的通信模式,具有固定的读端fd[0]和写端fd[1].
(3)管道可以看成是一种特殊的文件,对于他的读写可以使用文件IO,如read,write。
(4)管道是基于文件描述符的通信方式。当一个管道建立时,他会创建两个描述符fd[0],fd[1],其中fd[0]固定用于读管道,而fd[1]固定用于写管道。
1.2函数接口
int pipe( int fd[2])
功能:创建无名管道
参数:文件描述符 fd[0]:读端 fd[1]:写端
返回值:成功 0
失败 -1
#include <unistd.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
// fd[0] 代表读端 ,fd[1]代表写端
int fd[2] = {0};
char buf[65536] = "";
// 创建无名管道
int n = pipe(fd);
// 判断无名管道是否创建成功
// 若成功,返回值为0;失败,返回值为 -1
if (n < 0)
{
perror(" pipe error");
return -1;
}
// 查看管道读写端的文件描述符
printf("fd[0]:%d fd[1]:%d \n", fd[0], fd[1]);
// 通过fd[1]端向管道中写
write(fd[1], "hello world", 11);
// 通过fd[0]端从管道中读
read(fd[0], buf, 11);
printf("%s \n", buf);
return 0;
}
1.3注意事项
(1)当管道中无数据,读操作会阻塞。
当管道中有数据,关闭写端,可以将数据读出
当管道中无数据,关闭写端,读操作会立即返回
(2)管道中写满(管道大小64k)再写数据会阻塞,只有用大于4k空间之后,才可以继续写数据
(3)只有当管道读端存在时,向管道中写数据才有意义,否则会导致管道破裂。向管道中写入数据昵称会收到来自内核的SIGPIPE信号(通常是broke pipe 错误)。
2.有名管道
2.1特点
(1)有名管道可以使互不相关的两个进程互相通信
(2)有名管道可以通过路径名来指出,并且在文件系统中可见,但内容存放在内存中,但是读写数据不会在文件中,而是在管道中。
(3)进程通过文件IO来操作有名管道
(4)有名管道遵循先进先出原则
(5)不支持如lseek()操作
2.2函数接口
int mkfifo( constchar *filename, mode_t mode);
功能:创健有名管道
参数:filename:有名管道文件名
mode:权限
返回值:成功:0
失败:-1,并设置errno号
注意对错误的处理方式:
如果错误是file exist时,注意加判断,如:if(errno == EEXIST)
注:函数只是在路径下创建管道文件,往管道中写的数据依然写在内核空间。
先创建有名管道,然后用文件IO操作:打开、读写和关闭。
2.3注意事项
(1)只写方式打开,阻塞,一直到另一个进程把读打开
(2)只读方式打开,阻塞,一直到另一个进程把写打开
(3)可读可写,如果管道中没有数据,读阻塞。
// 1. `O_RDONLY`:只写方式打开阻塞。这表示该文件描述符以只读方式被打开,
// 如果尝试写入数据到该管道,会一直阻塞,直到另一个进程使用写方式打开该管道。
// 2. `O_WRONLY`:只读方式打开阻塞。这表示该文件描述符以只写方式被打开,
// 如果尝试从该管道读取数据,会一直阻塞,直到另一个进程使用读方式打开该管道。
// 3. `O_RDWR`:可读可写。
// 如果管道中没有数据可读,读取操作会阻塞,直到有数据可读;
// 如果管道已满,写入操作也会阻塞,直到有足够的空间可写。
2.4读写示例
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
int fd;
char buf[32] = "";
// 创建管道文件
int n;
n = mkfifo("fifo", 0666);
// 判断管道文件是否创建成功
if (n < 0)
{
// 如果错误号errno为EEXIST则代表管道文件已存在
// 如果管道文件已存在,则打印句提示语句而不是走到return -1
if (errno == EEXIST)
{
printf("file exist\n");
}
else
{
perror("mkfifo err");
return -1;
}
}
printf("mkfifo success\n");
// 打开管道文件
fd = open("fifo", O_RDWR);
if (fd < 0)
{
perror("fifo open error");
return -1;
}
printf("fd = %d \n", fd);
// 读写操作
write(fd, "hello", 5);
read(fd, buf, 32);
printf("%s \n", buf);
return 0;
}
3.无名管道和有名管道的区别
无名管道 | 有名管道 | |
使用场景 | 只能用于具有亲缘关系的进程之间的通信 | 不相干的两个进程也可以 |
特点 | 半双工的通信模式 具有固定的读端fd[0]和写端fd[1]。 通过文件IO操作 管道是基于文件描述符的通信方式。 | 在文件系统中会存在管道文件,但是数据放在内核空间 通过文件IO进行操作 遵循先进先出,不支持lseek操作 |
函数 | pipe() 直接read、write | mkfifo() 先打开open,再读写read、write |
读写特性 | 管道中无数据,读阻塞 关闭写端,有数据读出,无数据立即返回 管道写满64k,写阻塞,直到有4k空间才能继续写入 关闭读端,写入会使管道破裂 | 只写方式打开会阻塞,一直到另一个进程把读方式打开 只读方式打开会苏俄,一直到另一个进程把写方式打开 可读可写,如果管道中无数据读会阻塞 |