【Linux】进程间通信(无名/有名管道及System V共享内存)

本文详细介绍了Linux系统中进程间通信的两种方式:匿名和命名管道,以及System V共享内存。重点讲解了匿名管道的使用、命名管道的创建和删除,以及共享内存的原理、创建、删除和优缺点。通过实例展示了如何利用这些通信方式进行数据传输和资源共享。
摘要由CSDN通过智能技术生成


需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。 


 目录

一、通信的相关概念

二、管道(半双工)

1、管道的概念

三、匿名管道(fork实现,用于父子及血缘关系进程间通信)

1、匿名管道的使用

2、匿名管道的读写情况

3、管道的特征

4、基于匿名管道的进程池

四、命名管道(open打开相同文件实现,可用于非血缘关系的进程间通信)

1、命名管道的创建及删除

1.1命令行创建命名管道

1.2程序内创建及删除命名管道

1.3基于命名管道的用户端发送,服务端接收

五、System V共享内存

1、共享内存(物理内存块+相关属性)的原理

2、共享内存相关命令

2.1查看共享内存(ipcs -m/-q/-s)

2.2删除共享内存(ipcrm -m shmnid)

3、创建/查看/删除/控制(删除)/关联共享内存

3.1形成key(ftok)

3.2创建共享内存(shmget)

3.3关联/卸载共享内存(shmat/shmdt)(关联类似malloc)

3.4控制(主要用移除)共享内存(shmctl)

4、利用共享内存进行进程间通信

5、共享内存的优缺点

5.1共享内存的优点

5.2共享内存的缺点

5.3共享内存的特点

5.4共享内存大小的建议

六、消息队列(了解)

1、获取消息队列(msgget)

2、控制消息队列(msgctl)

3、其他略

七、信号量(计数器)(了解)

1、信号量的本质

2、信号量的作用

八、IPC资源的管理方式


一、通信的相关概念

        进程之间具有独立性,进程间如果要发生通信,就需要打破这种独立性。进程间通信必定需要一块公共的区域用来作为信息的存放点,操作系统需要直接的或间接给通信进程双方提供内存空间,例如这块内存空间是文件系统提供的,那么就是管道通信,通信的本质就是让不同的进程看到同一份内存空间。

        进程间通信是为了完成:

        1、数据传输:一个进程需要将它的数据发送给另一个进程;

        2、资源共享:多个进程之间共享相同的资源;

        3、事件通知:一个进程需要向另一个或另一组进程发送消息,通知他们发送了某种事件(例如子进程终止时要通知父进程)

        4、进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

二、管道(半双工)

1、管道的概念

        管道是基于文件系统的通信方式,那么就从底层的角度看一下管道通信的原理:

        管道文件是内存级文件,不用访问磁盘进行文件加载,操作系统直接创建结构体对象及内核缓冲区。如上图例子,管道文件不必使用open进行打开,操作系统会创建文件结构体对象及其内核缓冲区,并将其放入父进程的文件描述符表中,父进程创建子进程后,父子进程便能基于管道这个内存级文件进行通信。

        管道只能单向通信

三、匿名管道(fork实现,用于父子及血缘关系进程间通信)

        通过上方管道的概念可知,通过父进程fork创建子进程,让子进程拷贝父进程中管道文件的地址,两个进程便能看到同一个管道文件,这个管道文件是一个内存级文件,并没有名字,所以被称为匿名管道。

        所以对待管道和对待文件一样,体现Linux一切皆文件的思想。

1、匿名管道的使用

#include <unistd.h>
int pipe(int pipefd[2]);//pipefd[2]是输出型参数
On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.
成功时返回零,错误时返回 -1,并适当地设置 errno。

        pipefd[2]是输出型参数,外边搞个pipefd[2]数组传进去,系统调用pipe结束后这个数组中存放的就是读/写的fd。

        子进程写入数据到管道,父进程读取管道数据代码。

#include <iostream>
#include <unistd.h>
#include <cassert>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
//父进程读取,子进程写入
int main()
{
    //第一步父进程创建管道
    int fds[2];
    int n=pipe(fds);
    assert(n==0);
    //第二步父进程fork()创建子进程
    pid_t id =fork();//fork之后,父进程返回值>0,子进程返回值==0
    assert(id>=0);
    const char* s="我是子进程,我的pid是:";
    int cnt=0;
    if(id==0)
    {
        close(fds[0]);//子进程关闭读取的fd
        //子进程的通信代码
        while(true)
        {
            char buffer[1000];//这个缓冲区只有子进程能看到
            snprintf(buffer,sizeof(buffer),"子进程第%d次向父进程发送:%s%d",++cnt,s,getpid());//向缓冲区buffer中打印
            write(fds[1],buffer,strlen(buffer));//子进程将缓冲区数据写入管道
            sleep(1);//每隔1秒写一次
            //break;
        }
        close(fds[1]);//如果break跳出循环,子进程将关闭写端
        exit(0);
    }
    close(fds[1]);//父进程关闭写入 
    //父进程的通信代码
    while(true)
    {
        char buffer[1000];//这个缓冲区只有父进程能看到
        //如果管道中没有数据,读取端再读,默认会阻塞当前读取的进程
        ssize_t s=read(fds[0],buffer,sizeof(buffer)-1);
        if(s>0)//s是read读取成功字节数
        {
            buffer[s]='\0';
            cout << "父进程的pid是:"<<getpid()<<" "<<buffer<<endl;
        }  
        else if(s==0)//如果子进程关闭写端,父进程将会输出“读完了”
        {
            //读到文件结尾
            cout<<"读完了"<<endl;
            break;
        }  
    }
    n=waitpid(id,nullptr,0);
    assert(n==id);
    close(fds[0]);//父进程读取fd用完记得关一下
    return 0;
}

2、匿名管道的读写情况

        1、如果管道中没有数据,读取端进程再进行读取,会阻塞当前正在读取的进程;

        2、如果写入端写满了,再写就会对该进程进行阻塞,需要等待对方对管道内数据进行读取;

        3、如果写入进程关闭了写入fd,读取端将管道内的数据读完后read的返回值为0,和谐退出;

        4、如果读关闭,操作系统会给写端发送13号信号SIGPIPE,终止写端。

3、管道的特征

        1、只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道;

        2、管道提供流式服务 ;

        3、进程退出,管道释放,所以管道的生命周期随进程

        4、内核会对管道操作进行同步与互斥

        5、管道是半双工。需要双方通信时,需要建立起两个管道

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒋灵瑜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值