linux环境编程-进程间通信(IPC)-管道

在介绍管道之前我们得先了解 什么 是进程间通信,先看一个 视频 缓解一下气氛

一.概念: 

在linux环境下 每一个进程都有自己独立的地址空间,彼此之间相互独立,任何一个进程的全局变量在另一个进程中都看不到,所有进程之间不能相互访问,要交换数据必须通过内核(kernal),在内核中开辟一块缓冲区,进程1 把数据拷贝进内核空间,进程2把数据再从 内核空间读走,内核提供的这种机制就是所谓的 进程间通信(IPC)

 

二.IPC的方式:【后面我都会逐一详细介绍原理和代码实现】

进程间要完成数据的传递要借助操作系统提供的特殊方式完成,如: 文件,管道,内存映射,消息队列,本地套接字,信号,有名管道。随着计算机的发展,一些方式 由于过于落后或者 缺陷逐渐被淘汰,或者弃用,现在通常用的 IPC方式有:

  • 管道:使用最简单
  • 信号:开销最小(但是很不稳定,而且在linux下,信号机制对线程的支持并不是很好)
  • 共享内存:最快(本身是基于内存的读写)
  • 本地套接字:最稳定
  • 消息队列:可以定义自己的数据格式
  • 普通文件读写:开销比较大,不稳定被淘汰

 

三.管道

  1. 管道又分为两种,匿名管道和有名管道【其实就是一个是有血缘关系的,一个用于没有血缘关系的】。本质就是一个伪文件【实际为内核的缓冲区】
  2. 由两个文件描述符引用,一个表示读端,一个表示写端。
  3. 规定数据从管道的写端流入,从读端流出。
  4. 原理:管道实则是内核使用的环形队列机制,借助内核缓冲区(4k)实现
  5. 局限性:
  • 1.数据自己读不能自己写(除非又两个管道)
  • 2.数据一旦被读走,便不在管道之中,不可以反复读取。
  • 3.由于管道是半双工的通信方式,因此数据只能单向流动。

 

四.我们先来介绍管道的第一种,匿名管道

1.创建匿名管道

       int pipe(int pipefd[2]),  成功 return 0;失败 return -1,并设置errno

2.使用细节

1)函数调用成功后,得到 两个pipefd,一个读,一个写,无需open,但是要手动的 close, 规定,pipefd[0] 读端,pipefd[1] 写端和进程的文件描述符类似的。向管道文件读写实质就是 对内核缓冲区的读写。

2)读管道:管道中有数据,read返回实际读到的字节数;如果没有数据并且写端关闭,那就返回0;如果没有数据,但写端没有关闭,那就阻塞等待。

3)写管道:如果读端关闭的,进程异常终止(SIGPIPE【这个信号,还会在网络中触发,当client异常断开的时候】);如果读端打开的,但是pipe这个 管道满了,就等读端把数据读走,腾出空间继续来写,处于阻塞【比较少见】; 如果 没有满 就继续写,返回写入的字节数。

3.代码Demo

#include <iostream>
#include <unistd.h>
#include <string.h>

using namespace std;

#define PIPE_READ           0
#define PIPE_WRITE 1


int
main(int argc, char *argv[])
{
    int pipefd[2];
    pid_t pid = -1;
    if (pipe(pipefd) == -1){
        perror("creat pipe error");
        exit(0);
    }else cout << "pipe success" << endl;
        pid = fork();

        if(pid == 0){// read
            char buf[1024];
            close(pipefd[PIPE_WRITE]);
            ssize_t size = 0;
            do {
                sleep(1);
                size = read(pipefd[PIPE_READ], buf, sizeof(buf));
                if(size == 0){
                      printf("pipe is empty \n");
                      break;
                }
                buf[size] = '\0';
                cout << "size: " <<    size  << endl;
                printf("the text from pipe is: %s\n", buf);
            }while(1);
            close(pipefd[PIPE_READ]);

        }else if(pid > 0){// write 
                close(pipefd[PIPE_READ]);
                ssize_t lenth = 0;
                long pipebuf = fpathconf(pipefd[PIPE_WRITE],    _PC_PIPE_BUF);
                cout << "the pipe buf size is:" << pipebuf << endl; // 4k
                sleep(5);
                const char* str = "hello world";
                do{
                        lenth = write(pipefd[PIPE_WRITE], str, strlen(str));
                }while(1);
                close(pipefd[PIPE_WRITE]);
        }else{
                perror("fork error");
                exit(1);
        }


        return 0;
}

效果: 


 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值