管道和有命管道

管道的概念

  管道是一种最基本的IPC机制,作用于有血缘关系的进程之间(父子进程,爷孙进程,兄弟进程),完成数据传输。调用pipe系统函数即可创建一个管道。管道有如下特质

1.其本质是一个伪文件(实为内核缓冲区)
2.有两个文件描述符引用,一个代表读端,一个代表写写端
3.规定数据从管道的写端流入,从读端流出

管道的原理:管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:

1.数据一旦被读走,就不再管道中,不可反复读取
2.由于管道采用半双工通信方式。因此,数据只能在一个方向上流动
3.只能在有共有祖先的进程进程间使用

pipe函数

  创建管道

    函数原型:
         int pipe(int pipefd[2]); 
    参数:
        一个大小为2的int数组,如果管道创建成功,下标为0的文件描述符表示写端,下标为1的文件描述符为读端
    返回值:
       成功:0;失败:-1,设置errno

管道创建成功之后如何通信:

  1. 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。
  2. 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道
  3. 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。

管道示例代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    int fd[2];
    pipe(fd);
    pid_t pid = fork();

    if(pid == 0){
        //son 
        sleep(3);
        close(fd[0]);//关闭读端
        printf("child write\n");
        write(fd[1],"hello\n",6);
        
        while(1){
            sleep(1);
        }
        close(fd[1]); 
    }else if(pid > 0){
        //parent 
        close(fd[1]);//关闭写端
        char buf[12]={0};
        while(1){
            printf("parent read\n");
            int ret = read(fd[0],buf,sizeof(buf));
            if(ret == 0){
                printf("read over!\n");
                break;
            }
            if(ret > 0){
                
                write(STDOUT_FILENO,buf,ret);
            }
        }
        int status;
        wait(&status);
        if(WIFSIGNALED(status)){
            printf("killed by %d\n",WTERMSIG(status));
        }
        //父进程只是关闭读写两端,但是不退出
        while(1){
            sleep(1);
        }
        close(fd[0]);
    }
    return 0;
}


管道的读写行为

   使用管道需要注意一下4中特殊情况(假设都是阻塞I/O)

1.如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0,close一次引用计数-1),而仍然有从管道读端写入的数据,那么管道中生于的数据都被读取之后,再次read返回0,就像读到文件末尾一样。
2.如果有指向管道写端的文件描述符没有关闭,而持有管道的写端的进程也没有向管道中写数据,这是有进程冲管道中读数据,那么管道中生于的数据被读取后,再次read会阻塞,知道管道中有数据可读了。
3.如果所有指向读端的文件描述符都关闭了,这是有进程向管道的写端write,那么进程会收到一个SIGPIPE信号,通常会导致进程异常终止。当然也可以对SIGPIPE信号进行捕捉,不终止进程。
4.如果有指向管道读端的文件描述符没关闭(管道读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。

管道缓冲区大小

可以通过 ulimit -a 命令来查看当前系统中创建管道文件所对应的内核缓冲区大小。

[root@VM_0_11_centos linux]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 3893
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 100001
pipe size (512 bytes, -p) 8         //这里 512个字节
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 3893
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

管道的优劣

优点:简单,相比信号,套接字实现进程间通信,简单很多。
缺点:

  1. 只能单向通信,双向通信需建立两个管道。
  2. 只能用于父子、兄弟进程(有共同祖先)间通信。该问题后来使用fifo有名管道解决。

FIFO

   FIFO通常被乘坐有名管道,以区分管道(PIPE)。管道只能用于有血缘关系的进程间通信。但通过FIFO,不想管的进程也能进行数据交换
   FIFO是Linux基础文件类型中的一种。但,FIFO文件在磁盘上没有数据块,仅仅用来标志一条内核通道。各个进程可以打开这个文件进行read/write,实际上是写在内核通道上。

创建方式
1.通过命令 mkfifo 来创建管道

mkfifo mkfifo(第二个参数为管道名)
[root@VM_0_11_centos linux]# mkfifo mkinfo
[root@VM_0_11_centos linux]# ll
total 28
-rwxr-xr-x 1 root root 8955 May 17 15:34 a.out
prw-r--r-- 1 root root 0 May 17 15:51 mkinfo

2.mkfifo文件也可以通过库函数来创建

 函数原型:
        int mkfifo(const char *pathname,  mode_t mode);
参数:
        pathname, 文件路径
        mode 文件权限
返回值:
        成功:0; 失败:-1

常见的文件I/O函数都可用于fifo。如:close、read、write、unlink等。

3.读写示例代码:
fifo_r.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char *argv[])
{
    if(argc != 2){
        printf("./a.out fifoname\n");
        return -1;
    }
    printf("begin oepn read...\n");
    int fd = open(argv[1],O_RDONLY);
    printf("end oepn read...\n");
    
    char buf[256];
    int ret;
    while(1){
        //循环读
        memset(buf,0x00,sizeof(buf));
        ret = read(fd,buf,sizeof(buf));
        if(ret > 0){
            printf("read:%s\n",buf);
        }
    }

    close(fd);
    return 0;
}

fifo_w.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char * argv[])
{
    if(argc != 2){
        printf("./a.out fifoname\n");
        return -1;
    }
    
    // 当前目录有一个 myfifo 文件
    //打开fifo文件
    printf("begin open ....\n");
    int fd = open(argv[1],O_WRONLY);
    printf("end open ....\n");
    //写
    char buf[256];
    int num = 1;
    while(1){
        memset(buf,0x00,sizeof(buf));
        sprintf(buf,"xiaoming%04d",num++);
        write(fd,buf,strlen(buf));
        sleep(1);
        //循环写
    }
    //关闭描述符
    close(fd);
    return 0;
}



©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 一、Linux系统概述 不加引号可理解为宏,直接替换,单引号中特殊字符会被解释为普通字符,双引号中$,,'还是特殊...
    赤果_b4a7阅读 1,464评论 0 2
  • 前言 管道是UNIX环境中历史最悠久的进程间通信方式,也是最简单的进程间通信方式,一般用来作为IPC的入门,最合适...
    GeekerLou阅读 1,139评论 0 6
  • 一般,进程之间交换信息的方法只能是经由fork或exec传送打开文件,或者通过文件系统。而进程间相互通信还有其他技...
    丶Em1tu0F阅读 1,405评论 1 1
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,718评论 0 10
  • 一百天看100本书,《跟刘备学用人心计,跟曹操学做事手腕》曹操则是我们做事的楷模,他的一生中处处体现着做事的智慧与...
    张樱漫阅读 60评论 0 0