管道(PIPE->FIFO) 内核帮你创建和维护
管道的特点:
- 管道是半双工的,也就是同一时间数据只能从一端流向另一段。就像水一样,两端水同时流入管道,那么数据就会乱
- 管道的两端一端作为读端,一端是写端
- 管道具有自适应的特点, 默认会适应速度比较慢的一方,管道被写满或读空时速度快的一方会自动阻塞
pipe - create pipe
#include <unistd.h>
int pipe(int pipefd[2]);
// 也就只有两端,一端读,一端写
pipe用于创建管道,pipefd是一个数组,表示管道的两端文件描述符,pipefd[0]端作为读端,pipefd[1]作为写端。
pipe产生的是匿名管道,在磁盘的任何位置上找不到这个管道文件,而且匿名管道只能用于具有亲缘关系的进程之间通信(还要分亲缘关系)
一般情况下有亲缘关系的进程之间使用管道进行通信时,会把自己不用的一端文件描述符关闭
#include "../include/apue.h"
#define BUFSIZE 1024
int main(){
int pd[2];
char buf[BUFSIZE];
pid_t pid;
int len;
// 创建匿名管道
if(pipe(pd)<0)
err_sys("pipe()");
pid = fork();
if(pid == 0){ // 子进程 读取管道数据
// 关闭写端
close(pd[1]);
// 从管道中读取数据,如果子进程比父进程先被调度会阻塞等待数据写入
len = read(pd[0],buf,BUFSIZE);
puts(buf);
/***
* 管道fork之前创建
* 父子进程都有一份
* 所有退出之前要确保管道两端都关闭
* ***/
close(pd[0]);
exit(0);
}else{ // 父进程 向管道写入数据
// 关闭读端
close(pd[0]);
// 写端
write(pd[1],"Hello,world!",100);
close(pd[1]);
wait(NULL);
exit(0);
}
}
创建了一个匿名的管道,在pd[2]数组中凑齐了读写双方,子进程同样继承了具有读写双方的数组pd[2]
当关闭之后就是取决于我们需要对管道的数据流方向做准备。要么从子进程流向父进程,要么从父进程流向子进程。
mkfifo函数
mkfifo - make a FIFO special file (a named pipe)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
// pathname: 管道文件的路径和文件名
// mode: 创建管道文件的权限。还是老规矩,传入的mode值要与系统的umask值做运算(mode&~umask)
// 成功返回0,失败返回-1并设置errno
mkfifo函数用于创建命名管道,作用与匿名管道相同,不过可以在不同的进程之间使用,相当于对一个普通文件进行写操作就可以了。
这个管道文件是任何有权限的进程都可以使用的,两端都像操作一个普通文件一样对它进行打开、读写、关闭动作就可以了,只要一端写入数据另一端就可以读出来。
命名管道文件
#include "../include/apue.h"
#include <fcntl.h>
#define PATHNAME "./mkfifof.txt"
int main(void){
pid_t pid;
int fd = -1;
char buf[BUFSIZ] = "";
// 创建一个命名管道,通过ls -l查看这个管道的属性
if(mkfifo(PATHNAME,0664)<0){
err_sys("mkfifo");
}
fflush(NULL); // 刷新缓冲区
pid = fork();
if(pid<0)
err_sys("fork()");
if(!pid){
pid = fork(); // 继续fork 三个进程了
if(pid<0)err_sys("fork()2");
if(!pid) exit(0); // 爸爸走了
// child2
fd = open(PATHNAME,O_RDWR);
if(fd<0) err_sys("open()");
// 阻塞,等待条件满足
read(fd,buf,BUFSIZ);
printf("%s\n",buf);
write(fd," World!",8);
close(fd);
exit(0);
}else{
fd = open(PATHNAME,O_RDWR);
if(fd < 0) err_sys("open()");
// 写
write(fd,"hello",6);
sleep(1); // 要是不休眠就没有给另一个进程机会写,最后自娱自乐,第二个进程也打不开文件
read(fd,buf,BUFSIZ);
close(fd);
puts(buf);
// 这个进程最后退出,所以把管道文件删除,不然下次在创建的时候会报文件已存在的错误
remove(PATHNAME);
exit(0);
}
return 0;
}
看到了下面的创建,不是普通的文件,而是管道文件
prw-r--r-- 1 transcheung staff 0 2 14 11:41 mkfifof.txt
协同进程
管道是半双工的 两进程一个只能读,一个只能写
要实现双工通信,必须采用两个管道,一个进程对一个管道只读,对另一个管道只写。
#include "../include/apue.h"
#define BUFSIZE 1024
int main(){
int pd[2];
int ipd[2];
char buf[BUFSIZE];
char dbuf[BUFSIZE];
pid_t pid;
int len;
// 创建匿名管道
if(pipe(pd)<0)
err_sys("pipe()");
if(pipe(ipd)<0) err_sys("pipe2");
pid = fork();
if(pid == 0){ // 子进程 读取管道数据
// 关闭写端
// close(pd[1]);
// 从管道中读取数据,如果子进程比父进程先被调度会阻塞等待数据写入
//len = read(pd[0],buf,BUFSIZE);
// puts(buf);
/***
* 管道fork之前创建
* 父子进程都有一份
* 所有退出之前要确保管道两端都关闭
* ***/
close(pd[0]);
write(pd[1],"hello,child!",15);
// sleep(10);
//sleep(10);
len = read(ipd[0],dbuf,BUFSIZE);
puts(dbuf);
close(pd[1]);
close(ipd[0]);
exit(0);
}else{ // 父进程 向管道写入数据
// 关闭读端
//close(pd[0]);
// 写端
// write(pd[1],"Hello,world!",15);
close(pd[1]);
len = read(pd[0],buf,BUFSIZE);
puts(buf);
// 关闭读端
// sleep(5);
write(ipd[1],"hello parent!",BUFSIZE);
close(pd[0]);
close(ipd[1]);
wait(NULL);
exit(0);
}
}
两个管道,实现你来我往,mkfifo同理,两个文件就好了。
酷客网相关文章:
评论前必须登录!
注册