美文网首页
Linux pipe 管道

Linux pipe 管道

作者: 付凯强 | 来源:发表于2023-01-12 19:36 被阅读0次

引言

pipe是Linux系统跨进程通信的一种方式。管道分为匿名管道和有名管道。这里我们说的是匿名管道。作用于有血缘关系的进程之间,即必须有相同的祖先,这里使用父进程和子进程来举例说明。
匿名管道是单向的,分为读端和写端,通过调用pipe系统函数实现。
数据方面一个进程只能读或者写,不能自己写自己读。
向管道文件读写数据其实是在读写内核缓冲区。

pipe函数

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

pipe() 创建一个管道,一个可用于进程间通信的单向数据通道。 数组 pipefd 用于返回两个指向管道末端的文件描述符。 pipefd[0] 指的是管道的读端。 pipefd[1] 指的是管道的写端。 写端把数据写入管道,直到读端读取数据。
成功时,返回零。 出错时,返回 -1,并适当设置 errno。
函数执行完成,会生成r/w两个文件描述符。无需open,但需手动close。pipefd[0]即读端文件描述符,pipefd[1]即写端文件描述符。

父子进程通信

  1. 管道创建成功以后,创建该管道的进程(父进程)和子进程同时掌握着管道的读端和写端。
  2. 父进程关闭读端,子进程关闭写端。父进程写入数据,子进程读取数据。由于管道是单向的,数据从写端输入,从读端输出,从而实现进程间通信。

示例

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main(void)
{
    pid_t pid;
    char buf[15];
    int fd[2];
    char *p = "test for pipe\n";
    if (pipe(fd) == -1)
        sys_err("pipe");
    pid = fork();

    if (pid < 0) {
        sys_err("fork err");
    } else if (pid == 0) {
        printf("i am child begin\n");
        printf("i am child.my pid = %d\n",getpid());
        close(fd[1]);
        int len = read(fd[0], buf, sizeof(buf));
        write(STDOUT_FILENO, buf, len);
        close(fd[0]);
        printf("i am child end\n");
    } else {
        printf("i am parent begin\n");
        printf("i am parent.my pid = %d\n",getpid());
        close(fd[0]);
        write(fd[1], p, strlen(p));
        wait(NULL);
        close(fd[1]);
        printf("i am parent end\n");
    }
    return 0;
}
  1. 利用write(STDOUT_FILENO, buf, len);输出打印子进程读取到的内容。
  2. 父进程利用wait(NULL);等待子进程执行结束再执行逻辑。

管道的读写

读管道

  1. 管道中有数据,read返回实际读取到的数据字节数。
  2. 管道中无数据
    2.1 管道写端关闭,read返回0(好像读到文件结尾)
    2.2 管道写端未全部关闭,但未写入数据,read阻塞等待,直到读取到数据,此时让出cpu

写管道

  1. 管道读端全部关闭,write会导致进程异常终止,除非捕获SIGPIPE信号。
  2. 管道读端没有全部关闭
    2.1 管道已满,write阻塞
    2.2 管道未满,write数据写入后返回写入的字节数

读管道示例

  • 2.1的示例:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main(void)
{
    pid_t pid;
    char buf[15];
    int fd[2];
    char *p = "test for pipe\n";
    if (pipe(fd) == -1)
        sys_err("pipe");
    pid = fork();

    if (pid < 0) {
        sys_err("fork err");
    } else if (pid == 0) {
        printf("i am child begin\n");
        printf("i am child.my pid = %d\n",getpid());
        close(fd[1]);
        int len = read(fd[0], buf, sizeof(buf));
        printf("len = %d\n",len);
        write(STDOUT_FILENO, buf, len);
        close(fd[0]);
        printf("i am child end\n");
    } else {
        printf("i am parent begin\n");
        printf("i am parent.my pid = %d\n",getpid());
        close(fd[0]);
        close(fd[1]);
//        write(fd[1], p, strlen(p));
        wait(NULL);
//        close(fd[1]);
        printf("i am parent end\n");
    }
    return 0;
}
i am parent begin
i am parent.my pid = 8790
i am child begin
i am child.my pid = 8793
len = 0
i am child end
i am parent end
  • 2.2 示例
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main(void)
{
    pid_t pid;
    char buf[15];
    int fd[2];
    char *p = "test for pipe\n";
    if (pipe(fd) == -1)
        sys_err("pipe");
    pid = fork();

    if (pid < 0) {
        sys_err("fork err");
    } else if (pid == 0) {
        printf("i am child begin\n");
        printf("i am child.my pid = %d\n",getpid());
        close(fd[1]);
        int len = read(fd[0], buf, sizeof(buf));
        printf("len = %d\n",len);
        write(STDOUT_FILENO, buf, len);
        close(fd[0]);
        printf("i am child end\n");
    } else {
        printf("i am parent begin\n");
        printf("i am parent.my pid = %d\n",getpid());
        close(fd[0]);
//        close(fd[1]);
//        write(fd[1], p, strlen(p));
        wait(NULL);
        close(fd[1]);
        printf("i am parent end\n");
    }
    return 0;
}
i am parent begin
i am parent.my pid = 8899
i am child begin
i am child.my pid = 8902

写管道示例

  • 1 示例
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main(void)
{
    pid_t pid;
    char buf[15];
    int fd[2];
    char *p = "test for pipe\n";
    if (pipe(fd) == -1)
        sys_err("pipe");
    pid = fork();

    if (pid < 0) {
        sys_err("fork err");
    } else if (pid == 0) {
        printf("i am child begin\n");
        printf("i am child.my pid = %d\n",getpid());
        close(fd[0]);
        close(fd[1]);
        int len = read(fd[0], buf, sizeof(buf));
        printf("len = %d\n",len);
        write(STDOUT_FILENO, buf, len);
//        close(fd[0]);
        printf("i am child end\n");
    } else {
        printf("i am parent begin\n");
        printf("i am parent.my pid = %d\n",getpid());
        close(fd[0]);
        write(fd[1], p, strlen(p));
        wait(NULL);
        close(fd[1]);
        printf("i am parent end\n");
    }
    return 0;
}
i am parent begin
i am parent.my pid = 10161
i am child begin
i am child.my pid = 10163
len = -1
i am child end
i am parent end

这里很奇怪,关闭读端后,写入管道数据没有进程崩溃。在管道读端关闭的情况下,写入数据,read函数返回的是-1。作为一个TODO吧。

  • 2.1 示例
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main(void)
{
    pid_t pid;
    char buf[15];
    int fd[2];
    char *p = "test for pipe\n";
    if (pipe(fd) == -1)
        sys_err("pipe");
    pid = fork();

    if (pid < 0) {
        sys_err("fork err");
    } else if (pid == 0) {
        printf("i am child begin\n");
        printf("i am child.my pid = %d\n",getpid());
        close(fd[1]);
        int len = read(fd[0], buf, sizeof(buf));
        printf("len = %d\n",len);
        write(STDOUT_FILENO, buf, len);
        close(fd[0]);
        printf("i am child end\n");
    } else {
        printf("i am parent begin\n");
        printf("i am parent.my pid = %d\n",getpid());
        close(fd[0]);
        for (int i = 0; i < 10000; ++i) {
            write(fd[1], p, strlen(p));
        }
        wait(NULL);
        close(fd[1]);
        printf("i am parent end\n");
    }
    return 0;
}
i am parent begin
i am parent.my pid = 10546
i am child begin
i am child.my pid = 10548
len = 15
test for pipe
ti am child end

参考

https://blog.csdn.net/tjcwt2011/article/details/123117549

相关文章

  • Linux 进程之间的通信方式

    linux使用的进程间通信方式 管道(pipe)、流管道(s_pipe)、无名管道(FIFO)、 套接字 sock...

  • Linux进程间通信(Interprocess Communic

    linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘...

  • Linux下进程通信 匿名管道pipe

    匿名管道(pipe): 匿名管道(pipe)是Linux支持的最初Unix IPC形式之一 匿名管道进行父子进程之...

  • linux下进程间通信的几种主要手段简介

    linux下进程间通信的几种主要手段简介: 1.管道(Pipe)及有名管道(named pipe):管道可用于具有...

  • Android/Linux进程间通信方式

    Linux中 管道( pipe ): 管道包括三种: 普通管道PIPE: 通常有两种限制,一是单工,只能单向传输;...

  • Linux pipe 管道

    引言 pipe是Linux系统跨进程通信的一种方式。管道分为匿名管道和有名管道。这里我们说的是匿名管道。作用于有血...

  • 管道命令

    参考linux shell 管道命令(pipe)使用及与shell重定向区别、管道命令 管道命令操作符是:”|”,...

  • Linux的管道命令

    Linux的管道命令 管道命令(Pipe) 双向重定向 字符转换命令:tr,col,join,paste,expand

  • Linux进程间通信

    Linux进程间通信的概念 linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named p...

  • 记一次YY笔试中卡住得知识点

    linux下线程通信的方式有哪些? 1.管道(pipe)/namedpipe(有名管道) 2.信号(signal)...

网友评论

      本文标题:Linux pipe 管道

      本文链接:https://www.haomeiwen.com/subject/pmwbcdtx.html