linux——进程间通讯(管道)

本文详细介绍了管道通信的概念,包括无名管道和有名管道的工作原理及应用。通过实例演示了如何使用pipe函数实现父子进程间的实时通信,以及如何利用命名管道实现任意两个进程之间的通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

管道简介

概念:管道文件处在内存上,分为有名管道无名管道
一般来说,无名管道在父子进程间进行通讯使用
有名管道可以再任意两个进程间进行通讯使用

因为管道处在内存上,所以对管道的读写操作都是直接对内存进行操作,十分的快捷方便。

管道也是一种半双工,意为可以双方向通行,但是同一时刻只有一个方向进行通行。

无名管道

在一个进程中进行通讯是十分简单的,只要一个函数读入,一个函数输出就可以了。在学习过文件之后,也可以很轻易的进行进程间通讯,只要一个进程给文件写数据,另一个进程从文件读数据就可以了,但是这样做并不能实时通讯,使用管道的话,就可以进行实时通讯了。

使用管道需要调用名为pipe的函数

#include<unistd.h>
int pipe(file_discriptor[2]);

这样我们就可以创建出一个无名管道,pipe函数的参数是一个由两个整型类型的文件描述符组成的数组的指针。该函数在数组中填上两个新的文件描述符后返回0,失败则返回-1并设置errno来表明失败的原因。
其中file_discriptor[0]用来读管道中的数据,file_discriptor[1]用来给管道中写入数据。
这里写图片描述
下面我们用pipe函数来创建一个管道并使用它

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>

int main()
{
    int fd[2];
    pipe(fd);//只要有一个int型的含有两个元素的数组即可

    pid_t pid = fork();//创建一个子进程
    assert(pid != -1);

    if(pid == 0)//让子进程从管道中读数据
    {
        char buff[128] = {0};
        close(fd[1]);//关闭写端,因为子进程只负责读数据。
        read(fd[0],buff,128);//从管道中读取数据
        printf("child read = %s\n",buff);
        close(fd[0];
    }
    else{
        close(fd[0]);//父进程负责向管道输入数据,所以关闭读端
        char buff[128] = {0};
        printf("intput: ");
        fgets(buff,128,stdin);//从键盘输入数据
        write(fd[1],buff,strlen(buff));//向管道写入数据
        close(fd[1]);//写入数据结束之后,需要关闭管道
    }
    wait(NULL);//防止僵死进程产生
}

从代码看出,fork()之后,产生了一个子进程, 这时我们所做的操作就是给子进程传数据,让他读出来。
我们从主进程开始,先关闭了管道的读端,因为主进程只需要给管道中写入数据即可。我们通过fgets从键盘上获取输入的内容,然后通过write函数将内容写入管道中,然后关闭管道的写端。
再看子进程,先关闭了管道的写端,因为子进程只负责读取管道中的内容,当管道中没有内容时,子进程会被阻塞,直到管道写端被关闭或者从管道中读到了数据,子进程就会进入下一步,最后将管道的读端也关闭掉,至此,管道被彻底关闭。

这里写图片描述

这里写图片描述

上述代码运行结果如下:

input : hello world
child read = hello world

命名管道

使用命名管道,我们就可以在不同的进程间而不是父子进程间进行通讯了,这就相当于两个从一个文件中读写数据,不同的是这种读写是实时进行的。

想要使用命名管道,我们需要先创建一个管道文件。
在命令行模式下,使用mkfifo+文件名,即可创建一个命名管道。

mkfifo fifo

首先我们先创建一个名为fifo的命名管道
在这里我们同打开文件一样,需要使用open(),close()函数
在这里我们不使用O_RDWR模式打开一个管道,因为管道只用于单向通讯,如果使用了,那么这个进程就会从管道读回自己的输出

a.c

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

int main()
{
    int fd = open("fifo",O_WRONLY);//第一个参数是我们需要打开的文件
                                   //第二个参数表示为只写打开
    assert(fd = -1);
    printf("fd = %d\n",fd);//打印文件描述符的值   3为管道文件描述符

    char buff[128] = {0};
    printf("input:");
    fflush(stdout);//刷新缓冲区

    fgets(buff,128,stdin);//从键盘输入数据
    write(fd,buff,strlen(buff));//将数据写入管道
    close(fd);
    exit(0);
}

a.c程序用来从键盘获得数据,然后将数据传入管道中

b.c

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

int main()
{
    int fd = open("fifo",O_RDONLY);//第一个参数是我们需要打开的文件
                                   //第二个参数表示为只读打开
    assert(fd = -1);
    printf("fd = %d\n",fd);

    char buff[128] = {0};
    read(buff,fd,127);//从管道中读入数据
    printf("read: %s\n",buff);
    close(fd);
    exit(0);
}

b.c程序用来从管道中读出数据并打印

*

  • 当我们单独打开a.out或者b.out时,程序会被阻塞,并且不会将fd的值打印出来,这是因为管道需要一个写端和一个读端,只有当两端同时打开时,进程才能通讯,这时会在屏幕上打印出fd = 3的字样
  • 当管道的两端都打开后,从a.out中输入”hello world”,b.out便会向屏幕输出”hello world”

*
最终的输入输出结果应为:
a.c
fd = 3;
input: hello world

b.c
fd = 3;
read: hello world

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值