Linux匿名管道及实例

举报
码农爱学习 发表于 2021/12/03 23:21:57 2021/12/03
【摘要】 匿名管道,也称管道,是Linux下最常见的进程间通信方式之一。匿名管道在系统中没有实名,它只是进程的一种资源,会随着进程的结束而被系统清除。

匿名管道,也称管道,是Linux下最常见的进程间通信方式之一。匿名管道在系统中没有实名,它只是进程的一种资源,会随着进程的结束而被系统清除。

1 管道的创建与关闭

Linux中使用pipe()函数创建一个匿名管道,其函数原型为:

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

创建成功返回0,出错返回1。参数fd[2]是一个长度为2的文件描述符数组,fd[1]写入端的文件描述符,fd[0]读出端的文件描述符。

可以使用文件I/O函数read()和write()读管道进行读写,使用close()函数关闭管道两端。

示例,create_pipe.c:

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
​
int main(void)
{
    int fd[2];
    char str[256];
    if((pipe(fd))<0)
    {
        printf("create the pipe failed!\n");
        exit(1);
    }
    write(fd[1], "create the pipe sucessfully!\n", 31);
    read(fd[0], str, sizeof(str));
    printf("%s", str);
    printf("pipe file descriptors are%d,%d\n", fd[0], fd[1]);
    close(fd[0]);
    close(fd[1]);
​
    return 0;
}

编译后执行:

$ ./create_pipe
create the pipe sucessfully!
pipe file descriptors are3,4

程序中使用pipe函数建立了一个匿名管道fd,之后向管道一端写入数据并从另一端读出数据,将数据输出到标准输出,在程序的最后使用close函数关闭管道的两端。

2 进程间管道的读写

单独对一个进程进行管道的读写是没有实际意义的,管道的应用体现在父子进程兄弟进程之间的通信。

子进程的创建可以通过fork()函数完成,fork()函数原型为:

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

若创建成功,父进程中返回子进程ID,子进程中返回0;若创建出错返回-1。

2.1 父子进程间管道的读写

父进程利用管道向子进程发送消息,使用pipe函数建立管道,使用fork函数创建子进程,在父进程中维护管道的数据方向,并在父进程中向子进程发送消息,parent_pipe_child.c:

#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<limits.h>
#include<stdlib.h>
#include<string.h>
#define BUFSIZE PIPE_BUF
​
void err_quit(char *msg)
{
    printf(msg);
    exit(1);
}
​
int main(void)
{
    int fd[2];
    char buf[BUFSIZE] = "hello my child!\n";
    pid_t pid;
    int len;
​
    // create a pipe
    if((pipe(fd)) < 0)
        err_quit("pipe failed\n");
​
    // create a son process
    pid = fork();
    if(pid<0)
        err_quit("fork failed\n");
    // parent process do this
    else if(pid>0)
    {
        close(fd[0]);// father process close read port (fd[0])
        write(fd[1], buf, strlen(buf));// write to pipe
        printf("I am parent process(ID:%d),write pipe ok\n", getpid());
        exit(0);
    }
    // son process do this
    else //(pid == 0)
    {
        close(fd[1]);// son process close itself write port (fd[1])
        len = read(fd[0], buf, BUFSIZE);// read from pipe
        if(len<0)
            err_quit("process failed when read a pipe\n");
        else
        {
            printf("I am son process(ID:%d),read pipe ok\n", getpid());
            write(STDOUT_FILENO, buf, len);
        }
        exit(0);
    }
​
}

编译后执行:

$ ./parent_pipe_child
I am parent process(ID:4953),write pipe ok
I am son process(ID:4954),read pipe ok
hello my child!

上述程序使用pipe加fork组合,实现父进程到子进程的通信,程序在父进程段中关闭了管道的读出端,并相应地在子进程中关闭了管道的输入端,从而实现数据从父进程流向子进程

2.2 兄弟进程间管道的读写

管道在兄弟进程间传递数据,brother_pipe.c:

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<limits.h>
#include<string.h>
#define BUFSIZE PIPE_BUF
​
void err_quit(char *msg)
{
    printf(msg);
    exit(1);
}
​
int main(void)
{
    int fd[2];
    char buf[BUFSIZE] = "hello my brother!\n";
    pid_t pid;
    int len;
​
    // create pipe
    if((pipe(fd))<0)
        err_quit("pipe failed\n");
​
    // create the son process1
    pid = fork();
    if(pid < 0)
        err_quit("fork failed\n");
    else if(pid == 0)// son process1
    {
        close(fd[0]);// close read port
        write(fd[1], buf, strlen(buf));// write
        printf("I am son process1(ID:%d), write pipe ok\n", getpid());
        exit(0);
    }
​
    // create the son process2
    pid = fork();
    if(pid < 0)
        err_quit("fork failed\n");
    else if(pid > 0)
    {
        close(fd[0]);// close read port
        close(fd[1]);// close write port
        printf("I am parent process(ID:%d), close my pipe\n", getpid());
        exit(0);
    }
    else
    {
        close(fd[1]);// close write port
        len = read(fd[0], buf, BUFSIZE);// read
        printf("I am son process2(ID:%d), read pipe ok\n", getpid());
        write(STDOUT_FILENO, buf, len);
        exit(0);
    }
​
    return 0;
}

编译后执行:

$ ./brother_pipe
I am parent process(ID:4962), close my pipe
I am son process1(ID:4963), write pipe ok
I am son process2(ID:4964), read pipe ok
hello my brother!

上述程序中父进程分别建立了两个子进程,在子进程1中关闭了管道的读出端,在子进程2中关闭了管道的输入端,并在父进程中关闭了管道的两端,从而构成了从子进程1到子进程2的管道。另外,程序中父进程创建第1个子进程时并没有关闭管道两端,而是在创建第2个子进程时才关闭管道,这是为了在创建第2个进程时,子进程可以继承存活的管道。

附:fork()函数的使用示例

#include <unistd.h>
#include <stdio.h>
int main ()
{
    pid_t fpid; //fpid表示fork函数返回的值
    int count=0;
​
    fpid=fork();
    if (fpid < 0)
        printf("error in fork!");
    // son process see fpid as 0
    else if (fpid == 0)
    {
        printf("I am the child process, my process id:%d\n",getpid());
        count++;
    }
    // parent process see fpid as a non 0 num
    else// (fpid > 0)
    {
        printf("I am the parent process, my process id: %d\n",getpid());
        count++;
    }
​
    printf("统计结果是: %d\n",count);
    return 0;
}

运行结果:

./forktest
I am the parent process, my process id: 5892
统计结果是: 1
I am the child process, my process id:5893
统计结果是: 1
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。