zoukankan      html  css  js  c++  java
  • Linux学习笔记(12)-进程间通信|匿名管道

      Linux的进程间通信有几种方式,包括,管道,信号,信号灯,共享内存,消息队列和套接字等……

      现在一个个的开始学习!

      ——————————————————————————————————————————————————

      管道是一个进程链接另一个进程的数据通道,它通常是把一个进程的输出,接到另一个进程的输入,从而传递数据。

      在Linux的终端上,用单竖线|来表示,那么,这个符号可以做什么呢?

      举个栗子,如果我用ps -ef命令,可以查看我当前所有的进程:

      

      正如上图表示,显示出来的东西太多了,让人眼花缭乱,如果想在其中找到自己想要的进程,比如看看sshd服务是否启动了,那绝对会找到我吐血。

      换一种方式,如果使用管道那就简单多了……

      首先,用ps -ef命令后,他的输出就是一大堆的进程列表,我用这个输出,作为别的命令的输入,比如grep命令,那么就能轻易找到自己想要的进程。

      ps -ef|grep sshd

      下面来试试……

      

      这样就很明显的看出,已经把进程中,拥有关键字sshd的进程给筛选了出来,而且还涂上了红色。一目了然,我的sshd服务已经启动了。

    ————————————————————————————————————————————————————————————————————————

      管道分为匿名管道命名管道两种,匿名管道主要用在两个拥有血缘关系的进程间通信,比如父子,爷孙……

      而命名管道主要用在两个陌生进程之间的通信。

      匿名管道是一种半双工管道,半双工就意味这,他在同一时间内,只能进程送信或者受信的一种,无法同时进行。

      

      管道这个功能,如果表现在程序中,那么需要用到下面这个函数:

      int pipe(int pipefd[2])

      其中参数pipefd[2]是一个文件描述符性质的数组,代表打开管道的两端,其中pipefd[0]为读入,pipefd[1]为写入

      现在写个程序,父进程使用管道向子进程发送一个信号,子进程收到后,在返回一个信号。

      因为一点小错误,这个程序写了将近一个小时……

      重点:管道的读取read和写入write,这两个函数都是阻塞操作的!

      重点中的重点:一定要在进程创立之前,建立好管道。

      重点中的重点中的重点:匿名管道是半双工,在通信开始前,一定要先关闭不需要的通道,在通信结束后,一定也要执行关闭。

      在匿名管道中,读进程和写进程初始都会拥有[0],[1],两个描述符各自一套,写程序时一定要注意在写处理里面 close(pi[0]),在读进程里面 close(pi[1]),在写进程写任务执行完之后务必 close(pi[1]),读进程读完之后务必 close(pi[0])。

      否则将会出现无限阻塞的问题,关于这个问题,害得我花费了一个小时……

      疑问:当一个匿名管道关闭之后,能不能再次重新打开呢?比如说用open(pi2[1])之后,在继续发送数据呢?

          我在网上找了好久,但没有看见这方面的描述,我感觉,这匿名管道总不能是一次性的吧?如果真是那样,那也太奢侈了!!

    #include<sys/wait.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    
    int main(int argc, char *argv)
    {
        int pi1[2];
        int pi2[2];
        pid_t pid_test;
        char buff[100];
        char buff2[100]={"儿子:你好,我是儿子!"};
        char buff1[100]= {"老子:你好,我是老子!"};
    
        if (pipe(pi1)== -1)
        {
            printf("管道1号创建失败!
    ");
            exit(0);
        }
        if (pipe(pi2) == -1)
        {
            printf("创建2号管道失败!
    ");
        }
        pid_test = fork();
        if (pid_test < 0)
        {
            printf("创建子进程失败!
    ");
            exit(0);
        }
        if (pid_test == 0)
        {
            printf("我是儿子,名叫:%d,我爹是:%d
    ",getpid(),getppid());
            write(STDOUT_FILENO,"
    ",1);
            close(pi1[1]);
            while(read(pi1[0],buff,1) > 0)
            {
                write(STDOUT_FILENO,buff,1);
            }
            write(STDOUT_FILENO,"
    ",1);
            close(pi1[0]);
            printf("儿子读完了!
    ");
            printf("儿子读完了!
    ");
            sleep(2);
            close(pi2[0]);
            write(pi2[1],buff2,strlen(buff2));
            close(pi2[1]);
            printf("儿子写完了!
    ");
            exit(EXIT_SUCCESS);
            exit(0);
        }
        else
        {
            printf("我是爹!我的ID是:%d,我儿子的ID是:%d
    ",getpid(),pid_test);
            sleep(2);
            close(pi1[0]);
            write(pi1[1],buff1,strlen(buff1));
            close(pi1[1]);
            printf("老子写完了!
    ");
            close(pi2[1]);
            while(read(pi2[0],buff,1) > 0)
            {
                write(STDOUT_FILENO,buff,1);
    
            }
            write(STDOUT_FILENO,"
    ",1);
            printf("老子读完了!
    ");
            close(pi2[0]);
            wait(NULL);
            exit(0);
        }
    
        return 0;
    }

      代码执行的结果如下:

       程序OK了!!

      

      今天,太累了!

  • 相关阅读:
    Vi 和 Vim
    The C Programming Language-Chapter 5 Pointers and Arrays
    C# 4.0开始,泛型接口和泛型委托都支持协变和逆变
    数据库中的锁 and java StampedLock ReadWriteLock
    NetCore and ElasticSearch 7.5
    网关项目 ReverseProxy
    异常捕获&打印异常信息
    刷新:重新发现.NET与未来
    2019 中国.NET 开发者峰会正式启动
    .NET开发者必须学习.NET Core
  • 原文地址:https://www.cnblogs.com/han-bing/p/6091560.html
Copyright © 2011-2022 走看看