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

一、进程

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的地方阻塞。

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

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

相关推荐
安大小万6 分钟前
C++ 学习:深入理解 Linux 系统中的冯诺依曼架构
linux·开发语言·c++
九品神元师22 分钟前
jupyter配置说明
linux·ide·jupyter
黯然~销魂41 分钟前
root用户Linux银河麒麟服务器安装vnc服务
linux·运维·服务器
菠萝炒饭pineapple-boss2 小时前
Dockerfile另一种使用普通用户启动的方式
linux·docker·dockerfile
Zfox_3 小时前
【Linux】进程间关系与守护进程
linux·运维·服务器·c++
laimaxgg3 小时前
Linux关于华为云开放端口号后连接失败问题解决
linux·运维·服务器·网络·tcp/ip·华为云
浪小满3 小时前
linux下使用脚本实现对进程的内存占用自动化监测
linux·运维·自动化·内存占用情况监测
东软吴彦祖3 小时前
包安装利用 LNMP 实现 phpMyAdmin 的负载均衡并利用Redis实现会话保持nginx
linux·redis·mysql·nginx·缓存·负载均衡
艾杰Hydra4 小时前
LInux配置PXE 服务器
linux·运维·服务器
慵懒的猫mi4 小时前
deepin分享-Linux & Windows 双系统时间不一致解决方案
linux·运维·windows·mysql·deepin