linux进程篇 (三) 进程间的通信1 管道通信

通信方式分4大类:


管道通信:无名管道 有名管道
信号通信:发送 接收 和 处理
IPC通信:共享内存 消息队列 信号灯
socke 网络通信

用户空间      进程A     <----无法通信---->      进程B
-----------------|--------------------------------------|--------------
                 |                                |
内核空间          |<------------->  对象 <--------------->|    

----------------------------------------------------------------------

//基于文件IO的思想
//open    打开或者创建一个文件,内核开辟一个buffer -->打开对象
//write    往buffer里面写
//read    从buffer读
//close    释放buffer

1. 进程间的管道通信

用户空间       进程A       <----无法通信---->       进程B
-----------------|--------------------------------------|--------------
              |                               |
内核空间        |<------------->  管道 <--------------->|    

----------------------------------------------------------------------

管道文件时一个特殊的文件,由队列来实现
open --> pipe
管道中的东西读完了,就删除了、
管道中如果没有东西可读,就会 读堵塞
管道中如果写满了,就会写阻塞

1.1 无名管道

无名管道用于父子进程带有亲缘关系的进程

#include <unistd.h>
int pipe(int fildes[2]);    //创建
//文件描述符 filds[0]-read--出队     filds[1]-write--入队

write();    //
read();        //
close(fd[0]);
close(fd[1]);

------------------------------
fd[1]write            fd[0]read
------------------------------

小例子

int main()
{
    int fd[2];    //pipe的2个文件描述符
    int ret;
    ret = pipe(fd);    //创建管道
    if(ret < 0){
        perror("pipe");
        return -1;
    }
    printf("fd[0] = %d, fd[1] = %d
",fd[0],fd[1]);
    return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int fd[2];
    int ret;
    const char *writebuf = "hello pipe";
    char readbuf[1024] = {0};

    //1,创建pipe
    ret = pipe(fd);
    if(ret < 0)
    {
        perror("pipe");
        return -1;
    }
    printf("fd[0] = %d,fd[1] = %d
",fd[0],fd[1]);

    //2.write
    ret = write(fd[1],writebuf,strlen(writebuf));
    if(ret < 0){
        perror("write");
    }
    //2.read
    ret = read(fd[0],readbuf,1024);
    if(ret < 0){
        perror("read");
        return -1;
    }

    printf("read: %s
",readbuf);

    //3.close
    close(fd[0]);
    close(fd[1]);
    return 0;
}

1.2 有名管道

  对于无名管道,pipe要在fork之前创建,这样fork的时候,会将fd[0]和fd[1]拷贝,这样两个进程就使用的是同2个设备描述符,如果pipe在fork之后创建,那个2个进程就会分别创建1个管道,操作的不是同一个管道文件,就没办法实行通信。

   也就是说,无名管道只能用于fork创建这样的父子进程, 如果无亲缘关系的进程,无名管道没办法进行通信,就只能使用有名管道。

  有名管道 即创建一个带有文件inode节点的管道文件 p, 该文件不占有内存空间,仅有一个文件节点, 当该节点被open时,才占用内存空间。

   mkfifo 只是在用户空间创建了一个管道文件,并非在内存空间创建管道,只有在open时,才在内存空间创建一个管道。

   注,有名管道两端成对打开时才会开始执行

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *path, mode_t mode);    //文件路径 文件权限
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    int ret;    //0=ok    -1=failes

    ret = mkfifo("./fifo",0755); //创建管道文件 路径+权限
    if(ret < 0){
        perror("mkfifo");
        return -1;
    }
    return 0;
}

例子

fifo.c 创建有名管道文件

lude <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    int ret;

    ret = mkfifo("./fifo",0755); //创建管道文件 路径+权限
    if(ret < 0){
        perror("mkfifo");
        return -1;
    }
    return 0;
}

first.c 进程1

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int fd;
    int process_int = 0;

    fd = open("./fifo",O_WRONLY);    //注,有名管道两端成对打开时才会开始执行
    if(fd < 0){
        perror("open");
        return -1;
    }
    puts("fifo open success.");

    for(int i=0;i<5;i++){
        puts("我是第一个进程");
    }
    sleep(5);
    process_int = 1;

    write(fd,&process_int,1);
    while(1);
    return 0;
}

second.c 进程2

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int fd;
    int process_int = 0;

    fd = open("./fifo",O_RDONLY);    //注,有名管道两端成对打开时才会开始执行
    if(fd < 0){
        perror("open");
        return -1;
    }
    puts("fifo open success.");
    
    read(fd,&process_int,1);
    while(process_int == 0);

    for(int i=0;i<5;i++){
        puts("我是第二个进程");
    }

    while(1);
    return 0;
}
原文地址:https://www.cnblogs.com/kmist/p/10635823.html