第三十八讲 管道
一、无名管道(pipe)
1、函数介绍
函数名称 | 函数功能 | 头文件 | 返回值 |
---|
int pipe(int pipefd[2]) | 创建无名管道 | unistd.h | 成功:0 失败:-1 |
2、特点
- 特殊文件,前面说过在 linux 下一切皆文件。而无名管道是一个没有名字的文件,无法使用 open 函数进行操作,但是可以使用 close 函数关闭。
- 只能通过子进程继承文件描述符的形式来使用
- 使用 write 和 read 函数对无名管道进行操作时,可能会阻塞进程
- 所有文件描述符被关闭之后,无名管道被销毁
3、使用步骤
- 父进程创建无名管道
- 创建子进程
- close 无用端口(单方面传输数据可以这样)
- 读写管道
- 关闭管道描述符
4、使用示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
pid_t pid;
int pipeFd[2];
int status;
char readBuf[100];
memset(pipeFd, '\0', sizeof(pipeFd));
/*创建管道*/
if(pipe(pipeFd) < 0)
{
printf("Create pipe failed!");
return -1;
}
/*创建进程*/
pid = fork();
if(pid < 0)
{
printf("Create sub process failed!");
return -1;
}
/*子进程监听管道消息*/
if(pid == 0)
{
/*关闭写通道*/
close(pipeFd[1]);
/*读取管道消息*/
memset(readBuf, '\0', sizeof(readBuf));
/*这里是阻塞的*/
if(read(pipeFd[0], readBuf, sizeof(readBuf)) > 0)
{
printf("Read data is :%s\r\n", readBuf);
}
close(pipeFd[0]);
exit(0);
}
/*父进程向管道内写入消息*/
if(pid > 0)
{
/*关闭读取通道*/
close(pipeFd[0]);
if(write(pipeFd[1], "hello!sub process!", strlen("hello!sub process!")) < 0)
{
printf("Write pipe failed!\r\n");
exit(1);
}
else
{
printf("Write pipe success!\r\n");
close(pipeFd[1]);
wait(&status);
exit(1);
}
}
return 0;
}
二、有名管道
1、函数介绍
函数名称 | 函数功能 | 头文件 | 返回值 |
---|
int mkfifo(const char *filename, mode_t mode) | 创建有名管道 | sys/types.h sys/stat.h | 成功:0 失败:-1 |
2、特点
- 有文件名,可以使用 open 函数打开s
- 任意进程间数据传输
- write 和 read 操作可能会阻塞进程
- write 具有"原子性"(会先判断管道内空间是否足以将数据全部写入进去,如果空间足够再去写入管道)
3、使用步骤
- 创建有名管道(mkfifo)
- 需要传输数据的进程打开有名管道(open),然后读写管道(read/write)
- 操作完关闭管道(close)
4、示例
读取代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(char *argc, char **argv)
{
int fd;
char readBuf[20];
/* 等待管道是创建*/
printf("Fifo read stard!\r\n");
while(access("my_fifo", F_OK)/* 头文件 #include <fcntl.h> #include <unistd.h>*/ == -1)
{
printf("Fifo is not created\r\n");
sleep(1); /*头文件 unistd.h*/
}
/*打开管道*/
fd = open("my_fifo", O_RDONLY);
if(fd < 0)
{
printf("Open fifo failed!\r\n");
exit(0);
}
/*读取管道内数据*/
memset(readBuf, '\0', sizeof(readBuf));
if(read(fd, readBuf, sizeof(readBuf)) > 0)
{
printf("Write fifo data is:%s\r\n", readBuf);
}
/*关闭管道*/
close(fd);
return 0;
}
写入代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(char *argc, char **argv)
{
int fd;
/* 判断管道是否存在*/
if(access("my_fifo", F_OK) == -1)
{
printf("Fifo is not created, start create fifo\r\n");
if(mkfifo("my_fifo", 0666) < 0)
{
printf("Create fifo failed!\r\n");
exit(-1);
}
printf("Fifo is created\r\n");
}
/*打开管道*/
fd = open("my_fifo", O_WRONLY);
if(fd < 0)
{
printf("Open fifo failed!\r\n");
exit(0);
}
printf("Open fifo success!\r\n");
/*读取管道内数据*/
if(write(fd, "Hello fifo!\r\n", strlen("Hello fifo!\r\n")) <= 0)
{
printf("Write fifo failed!\r\n");
exit(-1);
}
/*关闭管道*/
close(fd);
return 0;
}
小提示
细心的朋友可能会发现,在单独执行读或者写管道函数的时候,程序会阻塞在 open 函数。这是因为需要在另一端打开管道函数才能退出阻塞。这个可以通过命令查看 man mkfifo 里面有介绍。这里搬上原文
Once you have created a FIFO special file in this way, any process can
open it for reading or writing, in the same way as an ordinary file.
However, it has to be open at both ends simultaneously before you can
proceed to do any input or output operations on it. Opening a FIFO for
reading normally blocks until some other process opens the same FIFO
for writing, and vice versa. See fifo(7) for nonblocking handling of
FIFO special files.
|