Linux内核管道

管道(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]

当关闭之后就是取决于我们需要对管道的数据流方向做准备。要么从子进程流向父进程,要么从父进程流向子进程。

Linux内核管道

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同理,两个文件就好了。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!