Linux下进程间通信


Linux进程间的通信

  • 00.再说这个问题前,首先应该知道为什么要进程间通信呢?,它带给我们什么东西,致使我们去学习它呢?

1.数据传输:一个进程需要将它的数据发送给另一个进程,比如我再自己的一个网站的项目中,子进程进行程序替换,去执行爬取数据,然后将数据给父进程,然父进程进行展示。
2.事件通知:如当一个进程执行写文件操作后,需要告诉另一个去读文件的进程写操作已经完成了,另一个进程现在可以开始读取文件了。其中异步就是再数据准备好了,也从内核中拷贝到了用户空间了,此时可以都去了。
3.进程控制:当一个进程希望去管理另一个进程,当这个进程出现异常情况时,尝试去重启进程。也能时刻直到了进程的状态。
4.数据共享:用来交换两个进程的数据,实现数据的共享。但是可能要引入一些别的机制来确保其正常的交换(同步互斥)。

  • 01.进程间通信–匿名管道

1.什么是管道呢?请看下图
Linux下进程间通信_第1张图片
2.看下linux对匿名管道的定义
Linux下进程间通信_第2张图片
3.虾面通过一个实例代码,来看一下,我想就可以很好的了解匿名管道

int main()
{
    //1.创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret<0)
    {
        perror("pipe");
        return -1;
    }

    //2.从标准输入读取内容放入管道
    char buf[1024]= {0};
    read(0,buf,sizeof(buf)-1);
    //3.写入管道
    write(pipefd[1],buf,strlen(buf)); 
    //4.从管道读取内容
    memset(buf,0,sizeof(buf)-1);
    read(pipefd[0],buf,sizeof(buf)-1);
    //5.写到标准输出
    std::cout<

4.由上面的可知管道就是一个文件,一个进程写,一个进程读,从而是实现了"所谓的通信"。
5.上篇博客讲了进程的创建,那么结合上篇博客,利用fork来共享管道,从而实现父子进程的通信。

int main()
{

    //1.创建管道
    
    int pipefd[2];

    int ret = pipe(pipefd);
    if(ret<0)
    {
        perror("pipe");
        return -1;
    }

    //1.进行fork,创建子进程
    char buf[1024]={0};
    ret =fork();
    if(ret<0)
    {
        perror("fork");
        return -1;
    }
    else if(ret==0)
    {
        
        //2.子进程从标准输入读取内容,写入管道
        read(0,buf,sizeof(buf)-1);
        write(pipefd[1],buf,strlen(buf));
        memset(buf,0,sizeof(buf));
        close(pipefd[0]);
        close(pipefd[1]);
    }
    else
    {
        wait(NULL);
        //3.父进程从管道读取内容,写到标准输出
        read(pipefd[0],buf,sizeof(buf)-1);
        std::cout<

6.上面是再fork之前创建的管道,fork后父子进程共享管道,子进程去写,父进程取读,从而是实现了进程间通信。
7.总结一下匿名管道
a.匿名管道其实就是一个文件,用来两个进程进行沟通的,但是只能用于有亲缘关系的进程一般就是调用fork,完成父子进程间的通信。
b.匿名管道是提供的流式服务,面向字节流的
c.内核对管道内置了同步互斥
d.管道是半双工的,只能一方进行读,一方进行写,不能同时进行读写操作,这样在实际中效率是很差的。要实现全双工需要两个管道来完成。如图
Linux下进程间通信_第3张图片
e.管道的生命周期随进程,即进程结束了,管道也被销毁了

  • 02.进程间通信–命名管道

1.命名管道

a.命名管道也是一种文件,特殊的文件(FIFO文件)
b.可以用于任何两个进程间,不管是否有没有亲缘关系

2.命名管道的创建:

a.命令行创建:[skin@localhost ~]$ mkfifo filename
b.程序中创建:mkfifo("./filename",0644);
3.通过写一个简单的server/client来看一下,命名管道的用法
 //server.cc 
    int main()
 13 {
 14 
 15     //1.创建管道
 16     int ret =mkfifo("./filename",0644);
 17     if(ret<0)
 18     { 
 19         perror("mkfifo");
 20         return -1;
 21     } 
 22     //打开管道(默认时关闭的)
 23     int fd  =open("./filename",O_RDWR);
 24     if(fd<0)
 25     { 
 26         perror("open");
 27         return -1;
 28     } 
 29     char buf[1024]={0};
 30     while(1)
 31     { 
 32         ssize_t read_size= read(fd,buf,sizeof(buf)-1);
 33         if(read_size<0)
 34         { 
 35             std::cout<<"rend error\n";
 36             continue;
 37         } 
 38         else if(read_size>0)
 39         { 
 40             std::cout<<"client say : "<
    //client.cc 
    int main()
 13 {
 14 
 15     //1.打开命名管道
 16     int fd  =open("./filename",O_RDWR);
 17     if(fd<0)
 18     {
 19         perror("open");
 20         return -1;
 21     }
 22     char buf[1024]={0};
 23     while(1)
 24     {
 25 
 26         std::cout<<"please input : ";
 27         fflush(stdout);
 28         ssize_t read_size =read(0,buf,sizeof(buf)-1);
 29         if(read_size<0)
 30         {
 31             perror("read");
 32             continue;
 33         }
 34         else if(read_size>0)
 35         {
 36             write(fd,buf,strlen(buf));
 37         }
 38     }
 39 
 40     close(fd);
 41                                                                                                                                               
 42     return 0;
 43 }   

程序结果通过两个终端看一下
Linux下进程间通信_第4张图片

4.总结一下命名管道
a.管道通信可以不是亲缘关系,热议两个进程都可以的。
b.管道是面试字节流的
c.管道也是半双工的,内核默认提供同步互斥机制。
d.管道是以一个文件的全路径来命名的,默认时关闭的,使用应该手动打开
e.同样的,命名管道的生命周期随进程。


简述一下管道的读写规则:
a.当管道读段关闭,尝试去写,那么OS会默认发送一个SIGPIPE信号杀死进程
b.当管道的写段关闭,尝试去读,那么会直接当作已经读完了,rea返回0

  • 03进程间通信–共享内存

1.什么是共享内存?
a.共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。我个人理解就是直接在内存创建一个共享映射区,一旦映射到其他进程的地址空间,那么其也可以访问,省去了拷贝到内核,再通过内核的系统调用来进行访问获取。 b.共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的
2.共享内存示意图:
Linux下进程间通信_第5张图片
假设进程1在内存共享映射区放了val=10,那么一旦将这块区域映射到进程2的地址空间,那么进程2也是可以访问到的。
3.共享内存的函数
Linux下进程间通信_第6张图片
Linux下进程间通信_第7张图片
Linux下进程间通信_第8张图片
Linux下进程间通信_第9张图片
4.总结一下共享内存
Linux下进程间通信_第10张图片

  • 04.进程间通信–消息队列

Linux下进程间通信_第11张图片

  • 05.总结一下

Linux下进程间通信_第12张图片
1.所有进程间通信的本质,都是让不同的进程看到一块相同的内存,这样就达成了进程间通信。 2.进程间通信的目的主要是为了完成,数据传输,数据共享,进程控制等。 3.管道相对于IPC来讲,优点是所有的Linux实现都支持, 并且在最后一个访问管道的进程终止后,管道就被完全删除;缺陷是管道只允许单向传输或者用于父子进程之间. 4.IPC的优点是:功能强大,而且可以在任意进程间完成通信,缺陷就是如共享内存,消息队列都是随内核,占用内核资源


如果错误,可以私信,这里表示感谢!

你可能感兴趣的:(Linux)