欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

进程间通信的方式(一):管道

程序员文章站 2022-10-19 23:22:48
管道 (一).通信方式: 进程间通信又称IPC(Inter Process Communication),它可以通过文件 管道 有名管道 共享内存 消息队列 信号量 套接字这几...

管道

(一).通信方式:

进程间通信又称IPC(Inter Process Communication),它可以通过文件 管道 有名管道 共享内存 消息队列 信号量 套接字这几个方式进行通信,但是文件这种以及消息队列基本已被淘汰。

所以常用的通信方式有:

1.管道

2.信号

3.共享映射区

4.本地套接字

(二).管道基本概念:

而其中的管道机制,是属于最简单的一种通信方式。它适用于有血缘关系的进程之间的单向通信。它的本质是伪文件,是一段内核缓冲区。实现原理是内核使用环形队列,借助内核缓冲区实现。

当我们调用pipe()函数创建管道时,需要传入一个文件描述符数组,一个表示读端,一个表示写端。就好像一个管道一样,写方进程将数据写入,读方再通过管道将数据读出。既然规定了读和写的两端,以及是环形队列以及缓冲区实现,就证明了有一定的局限性。

1.数据不可反复读取,即读了之后在缓冲区中就没有了

2.半双工通信,只能单方向的传输数据

3.有血缘关系的进程之间通信

(三).使用管道进行通信:

创建管道的函数原型:int pipe(pipefd[2])

所需头文件:#include

参数pipefd[2]会返回两个文件描述符,一个用于读,另一个用于写。默认是fd[0]读,fd[1]写。如果创建管道成功,返回0,否则返回-1。

例子:

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

int main()
{
    int fd[2];
    pid_t pid;

    if(pipe(fd) == -1)
    {
        perror("pipe error:");
        exit(1);
    }

    pid = fork();
    if(pid == -1)
    {
        perror("fork error:");
        exit(2);
    }
    else if(pid == 0) //本例子中子进程写数据
    {
        close(fd[0]); //关闭读数据的文件描述符
        write(fd[1], "hello pipe!\n", strlen("hello pipe!\n")); //写入数据
    }
    else
    {
        close(fd[1]);
        char buf[102400];
        int ret = read(fd[0], buf, sizeof(buf)); //通过管道读出数据
        if(ret == 0)
        {
            printf("读到了文件末尾\n");
        }
        write(STDOUT_FILENO, buf, ret);  //输出到终端
    }
    return 0;
}
//输出结果:
hello pipe!
(五).注意事项:

在使用管道时,有几种特殊情况需要注意:

1.管道中没有数据时,如果管道写端全部关闭,那么此时read函数会返回0,如果管道写端没有全部关闭,那么此时read会阻塞等待数据。也就是说,在上面的例子中,如果子进程通过sleep函数睡眠10秒,父进程也会阻塞等待子进程写数据,因为此时子进程的写端仍处于开启状态。

2.管道读端全部关闭,进程会异常终止(可以理解为读数据的都没有了,那写数据也没有意义了)

3.管道已满时,写入会阻塞。

要知道管道只能在有血缘关系的进程之间通信,而有名管道恰可以用于无血缘关系的进程间通信。