管道的主要功能就是在不同进程中间完成数据传输工作。
pipe() 函数
头文件
#include<unistd.h>
函数原型
int pipe(int pipefd[2]);
//参数为文件描述符数组,无名管道的读写描述符就存于此。
//在文件中通过这两个文件描述符进行数据传输。
返回值
成功:0
失败:-1
特点:
- 特殊文件(没有名字),那当然无法使用open() ,但是可以使用close() 。
- 只能通过子进程继承文件描述符的方式来使用无名管道进行数据的传输。
- write() 和 read() 可能会阻塞进程。
read时,无名管道内没有数据,那么read会阻塞进程,直到无名管道有数据。
write向无名管道写数据时,无名管道的缓存区已经写满了,write函数所对应的进程就无法往无名管道里写程序,阻塞进程。直到无名管道的缓存区的数据被读走了之后,才能写。缓存区有任意的空间,write()就不会阻塞,直接写入。 - 所有的文件描述符被关闭后,无名管道被销毁。如,父进程、子进程中都有两个文件描述符,这四个文件描述符都被关闭以后,无名管道才会被销毁。
使用步骤
- 父进程调用pipe()函数,创建无名管道,并把管道的文件描述符记录在进程的文件描述符表里面。
- 父进程里面调用fork()函数,创建子进程。子进程会把上面父进程的文件描述表继承过来。
- 关闭无用端口,写的时候打开写文件描述符,关闭读文件描述符;读的时候相反。一般不会在一个进程里面同时打开读写两个文件描述符。
- 调用read() 或者 write() 读写端口。
- close() 关闭读写端口。
测试代码
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_DATA_LEN 256
int main()
{
pid_t pid;
int pipe_fd[2];
int status;
char buf[MAX_DATA_LEN];
const char data[] = "Pipe test program";
int real_read,real_write;
memset((void *)buf,0,sizeof(buf));
//创建管道
if(pipe(pipe_fd) < 0)
{
printf("Pipe create error.\n");
exit(1);
}
//创建一个子进程
if((pid = fork()) == 0)
{
//子进程关闭写描述符
close(pipe_fd[1]);
//子进程读取管道内容
//如果无名管道里没有内容,read将该子进程阻塞在此处
if((real_read = read(pipe_fd[0],buf,MAX_DATA_LEN)) > 0)
{
printf("%d bytes read from the pipe,it is '%s'\n",real_read,buf);
}
close(pipe_fd[0]);
exit(0);
}
else if(pid > 0)
{
//父进程关闭描述符
close(pipe_fd[0]);
if((real_write = write(pipe_fd[1],data,strlen(data))) != -1)
{
printf("Parent write %d bytes : %s\n",real_write,data);
}
//关闭父进程描述符
close(pipe_fd[1]);
//收集子进程退出信息
//阻塞等待子进程退出,子进程调用了exit(0)之后
wait(&status);
exit(0);
}
}
程序运行结果
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ gcc pipe.c
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ ls
a.out dd.c pipe.c
jl@jl-virtual-machine:~/test/11_1$ ./a.out
Parent write 17 bytes : Pipe test program
17 bytes read from the pipe,it is 'Pipe test program'
jl@jl-virtual-machine:~/test/11_1$
测试成功!