• Linux进程间通信-管道深入理解(转)


    原文地址:https://www.linuxidc.com/Linux/2018-04/151680.htm

    Linux进程通信系列文章将详细介绍各种通信方式的机制和区别

    1.进程间通信

    每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

    2、进程间通信方式

    一、进程间通信-管道 https://www.linuxidc.com/Linux/2018-04/151680.htm

    二、进程间通信-命名管道 https://www.linuxidc.com/Linux/2018-04/151681.htm

    三、进程间通信-消息队列 https://www.linuxidc.com/Linux/2018-04/151682.htm

    四、进程间通信-共享内存 https://www.linuxidc.com/Linux/2018-04/151683.htm

    3、进程间通信-管道(pipe)

     3.1 管道是如何通信的  

    (1)父进程创建管道,得到两个⽂件描述符指向管道的两端

    (2)父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。

    (3)父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。

    3.2 利用管道实现通信

    #include "stdio.h"
    #include "unistd.h"
    #include "string.h"

    int main(int argc, char* argv[])
    {
        int fd[2];
        int ret = pipe(fd);
        if (ret == -1)
        {
            perror("pipe error ");
            return 1;
        }

        pid_t pid = fork();
        if (pid == 0)  // child
        {
            close(fd[0]);
            int i = 0;
            char* msg = "i am child ";
            while (i < 5)
            {
                write(fd[1],msg,strlen(msg));
                sleep(2);
                i++;
            }

        }
        else if(pid > 0)
        {
            close(fd[1]);
            char buf[256] = {0};
            int j = 0;
            while (j < 5)
            {
                int n = read(fd[0],buf,256);
                if (n>0)  
                {  
                    buf[n] = '';  
                }  
                printf("%s",buf);
                j++;  
            }
        }
        else
        {
            perror("fork error ");
            return 1;
        }
        return 0;
    }

    运行结果:

     3.3 管道读取数据的四种的情况

    (1)读端不读,写端一直写

    (2)写端不写,读端一直读

    (3)读端一直读,写端关闭

    (4)写端一直写,读端关闭

    #include "stdio.h"
    #include "unistd.h"
    #include "string.h"
    #include "sys/wait.h"
    #include "sys/types.h"

    int main(int argc, char* argv[])
    {
        int fd[2];
        int status = 0;
        int ret = pipe(fd);
        if (ret == -1)
        {
            perror("pipe error ");
            return 1;
        }

        pid_t pid = fork();
        if (pid == 0)  // child
        {
            close(fd[0]);
            int i = 0;
            char* msg = "i am child ";
            while (i < 10)
            {
                write(fd[1],msg,strlen(msg));
                sleep(1);
                i++;
            }

        }
        else if(pid > 0)
        {
            close(fd[1]);
            char buf[256] = {0};
            int j = 0;
            while (j < 5)
            {
                int n = read(fd[0],buf,256);
                if (n>0)  
                {  
                    buf[n] = '';  
                }  
                printf("%s",buf);
                j++;  
            }
            close(fd[0]);
            ret = waitpid(pid,&status,0);
            printf("exit single(%d),exit(%d) ", status & 0xff, (status >> 8) & 0xff);  
        }
        else
        {
            perror("fork error ");
            return 1;
        }
        return 0;
    }

    运行结果:

    使用kill -l 查看13号信号,可以知道13号信号代表SIGPIPE。

    4、管道的特点

    (1)管道只允许具有血缘关系的进程间通信,如父子进程间的通信。

    (2)管道只允许单向通信。

    (3)管道内部保证同步机制,从而保证访问数据的一致性。

    5、管道的容量

    测试管道容量大小只需要将写端一直写,读端不读且不关闭fd[0],即可。

    #include "stdio.h"
    #include "unistd.h"
    #include "string.h"
    #include "sys/wait.h"
    #include "sys/types.h"

    int main(int argc, char* argv[])
    {
        int fd[2];
        int status = 0;
        int ret = pipe(fd);
        if (ret == -1)
        {
            perror("pipe error ");
            return 1;
        }

        pid_t pid = fork();
        if (pid == 0)  // child
        {
            close(fd[0]);
            int i = 1;
            while (i)
            {
                write(fd[1],"A",1);
                printf("pipe capacity: %d ",i++);
            }
            close(fd[1]);

        }
        else if(pid > 0)
        {
            close(fd[1]);
            waitpid(pid,NULL,0);
            close(fd[0]);
        }
        else
        {
            perror("fork error ");
            return 1;
        }
        return 0;
    }

    运行结果:

    由此可见,管道大小为64k

    本文永久更新链接地址https://www.linuxidc.com/Linux/2018-04/151680.htm

  • 相关阅读:
    VFIO PF SRIOV IOMMU UIO概念解释、关联
    集群节点间网络通信TIPC
    1. C语言中的数据结构.md
    第三讲. COTS包交换介绍
    SYSTick 定时器
    热电偶基础知识介绍-04
    附录1· 初识Linux操作系统
    热电偶冷端补偿
    珍惜是最宝贵的财富。
    CSS 设置标题文字只显示一行,多余显示省略号
  • 原文地址:https://www.cnblogs.com/lemaden/p/10438639.html
Copyright © 2020-2023  润新知