进程间通信、无名管道、有名管道

一、进程

1.1 进程间通信的概念

线程通信通过全局变量即可。

进程间通信是相互独立的,但是所有进程都共用一份内核空间,所以进程和进程之间的通信可以通过内核去进行。

1.2 进程间通信方式

共7种:

  1. 传统的进程间通信方式:
    1. 无名管道
    2. 有名管道
    3. 信号
  2. systemV版本的IPC进程间通信:
    1. 消息队列
    2. 共享内存
    3. 信号灯集
  3. BSD版本的:
    1. socket实现本地通信

1.3 无名管道

1.3.1 无名管道的概念和特性

无名管道在内核中开辟一块内存空间,用于进程间的通信。

无名管道创建之后,回想用户返回两个文件描述符,一个读端文件描述符,一个写端文件描述符。读端文件描述符,用于从管道中读取数据,写端文件描述符,用于向管道中写入数据。

无名管道只能用于亲缘间进程的通信。

无名管道大小是64K。

1.3.2 无名管道的API

cpp 复制代码
#include <unistd.h>
int pipe(int pipedf[2]);
功能:创建一个无名管道
参数:
    pipefd:保存内核返回的管道的两端
        pipedf[0]:管道的读端
        pipedf[1]:管道的写端
返回值:成功返回0,失败返回-1,置位错误码

1.3.3 无名管道运行实例:

cpp 复制代码
#include <my_head.h>

int main(int argc,const char *argv[]){
    int ret = 0;
    int pipedf[2] = {0};
    //创建无名管道
    ret = pipe(pipedf);
    if(-1 == ret){
        PRINT_ERR("create pipe error");
    }
    //创建子进程
    ret = fork();
    if(-1 == ret){
        PRINT_ERR("fork error");
    }
    else if(0 == ret){
        //子进程,关闭读
        char send_buf[128] = {0};
        close(pipedf[0]);
        while(1){
            fgets(send_buf,sizeof(send_buf),stdin);
            send_buf[strlen(send_buf)-1] = '\0';
            write(pipedf[1],send_buf,strlen(send_buf));
            if(!strcmp(send_buf,"quit"))
            break;
        }
        close(pipedf[1]);
    }else{
        //父进程,关闭写
        char recv_buf[128] = {0};
        close(pipedf[1]);
        while(1){
            memset(recv_buf,0,sizeof(recv_buf));
            read(pipedf[0],recv_buf,sizeof(recv_buf));
            if(!strcmp(recv_buf,"quit"))
            break;
            printf("我是父进程,我收到了数据[%s]\n",recv_buf);
        }
        close(pipedf[0]);
        wait(NULL);
    }

    return 0;
}

运行结果:

无名管道的读写特点:

如果读端关闭,向管道写数据:

管道破裂,祥管道写入数据的进程会收到管道破裂的信号,这个信号会杀死该进程。

如果独断打开(不读),一直写:

有多少写多少,管道满了之后(管道大小是164K),会在write的地方阻塞

如果写端不存在,读数据:

如果管道中有数据,就读数据,如果没有数据就立即返回。

如果写端存在(不写),读数据,有数据就读数据,没数据就在read的地方阻塞

1.4有名管道

1.4.1 有名管道的特点

有名管道在内核中开辟一块内存空间,用于进程间的通信。

有名管道创建之后,会在文件系统中创建一个管道文件。

两个进程想要进行通信的时候,可以通过open函数1打开管道文件,然后向管道中写入内容,或者读取内容,实现进程间的通信。

这个管道文件本质上是保存在内存上的。

有名管道可以用于任意进程间通信。

有名管道大小为64K。

2.4.2 创建有名管道的API

cpp 复制代码
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
功能:创建一个有名管道
参数:
    pathname:管道文件的路径和名字
    mode:创建文件的权限(mode & ~umask)
返回值:成功返回0,失败返回-1,置位错误码

mkfifo 管道文件名 --- 通过命令创建一个有名管道

1.4.3 有名管道使用示例

mkfifo.c

cpp 复制代码
#include <my_head.h>

int main(int argc,const char *argv[]){
    mkfifo("./fifo",0666);

    getchar();

    //system("rm fifo");
    remove("./fifo");//删除文件
    return 0;
}

read.c

cpp 复制代码
#include <my_head.h>

int main(int argc,const char *argv[]){
    int fd = 0;
    //1.打开管道文件,以只读的方式打开
    fd = open("./fifo",O_RDONLY);
    if(-1 == fd){
        PRINT_ERR("open fifo error");
    }
    char recv_buf[128] = {0};

    //2.开始循环读
    while(1){
        memset(recv_buf,0,sizeof(recv_buf));
        read(fd,recv_buf,sizeof(recv_buf));
        if(!strcmp(recv_buf,"quit"))
            break;
            printf("读到了数据[%s]\n",recv_buf);
    }
    close(fd);
    return 0;
}

write.c

cpp 复制代码
#include <my_head.h>

int main(int argc,const char *argv[]){
    int fd = 0;
    //1.以只读方式打开管道文件
    fd = open("./fifo",O_WRONLY);
    if(-1 == fd){
        PRINT_ERR("open fifo error");
    }
    char send_buf[128] = {0};
    //2.开始循环写 
    while(1){
        fgets(send_buf,sizeof(send_buf),stdin);
        send_buf[strlen(send_buf) - 1] = '\0';
        write(fd,send_buf,strlen(send_buf));
        if(!strcmp(send_buf,"quit"))
        break;
    }
    close(fd);
    return 0;
}

有名管道的读写特点:

如果读端没有打开,写管道:

在open的位置阻塞。

如果读端打开(不读),写管道:

有多少写多少,写满为止,写阻塞。

读端打开后关闭,写管道:

管道破裂,向写管道的进程发送管道破裂信号,杀死该进程。

如果写端没打开,读管道:

在open的位置阻塞。

写端打开(不写),读管道:

有数据就读数据,没数据,在read的地方阻塞。

写端打开后关闭,读管道:

有数据就读数据,没数据就立即返回。

相关推荐
我言秋日胜春朝★37 分钟前
【Linux】进程地址空间
linux·运维·服务器
C-cat.1 小时前
Linux|环境变量
linux·运维·服务器
yunfanleo1 小时前
docker run m3e 配置网络,自动重启,GPU等 配置渠道要点
linux·运维·docker
糖豆豆今天也要努力鸭2 小时前
torch.__version__的torch版本和conda list的torch版本不一致
linux·pytorch·python·深度学习·conda·torch
烦躁的大鼻嘎2 小时前
【Linux】深入理解GCC/G++编译流程及库文件管理
linux·运维·服务器
ac.char2 小时前
在 Ubuntu 上安装 Yarn 环境
linux·运维·服务器·ubuntu
敲上瘾2 小时前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
长弓聊编程2 小时前
Linux系统使用valgrind分析C++程序内存资源使用情况
linux·c++
cherub.2 小时前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
梅见十柒3 小时前
wsl2中kali linux下的docker使用教程(教程总结)
linux·经验分享·docker·云原生