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

一、进程

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

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

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

相关推荐
IC 见路不走1 小时前
LeetCode 第91题:解码方法
linux·运维·服务器
翻滚吧键盘1 小时前
查看linux中steam游戏的兼容性
linux·运维·游戏
小能喵1 小时前
Kali Linux Wifi 伪造热点
linux·安全·kali·kali linux
汀沿河2 小时前
8.1 prefix Tunning与Prompt Tunning模型微调方法
linux·运维·服务器·人工智能
zly35002 小时前
centos7 ping127.0.0.1不通
linux·运维·服务器
小哥山水之间3 小时前
基于dropbear实现嵌入式系统ssh服务端与客户端完整交互
linux
ldj20203 小时前
2025 Centos 安装PostgreSQL
linux·postgresql·centos
翻滚吧键盘3 小时前
opensuse tumbleweed上安装显卡驱动
linux
cui_win4 小时前
【内存】Linux 内核优化实战 - net.ipv4.tcp_tw_reuse
linux·网络·tcp/ip
CodeWithMe7 小时前
【Note】《深入理解Linux内核》 Chapter 15 :深入理解 Linux 页缓存
linux·spring·缓存