Linux多进程通信(1)——无名管道及有名管道使用例程

Linux多进程通信总结——进程间通信看这一篇足够啦!

管道是半双工通信,如果需要 双向通信,则需要建立两个管道,
无名管道:只能父子进程间通信,且是非永久性管道通信结构,当它访问的进程全部终止时,管道也随之被撤销
有名管道:进程间不需要有亲缘关系,是永久性管道通信结构,直到pclose才被关闭。(提供了一个路径名,以FIFO的形式存在于文件系统)

1.有名管道

int mkfifo(const char *pathname, mode_t mode);

有名管道创建完毕后,直接使用系统调用来操作即可进行读写等操作,同时也可以使用mkfifo(shell命令),来进行管道创建
打开管道:open
关闭管道:close
读数据:read
写数据:write

2.无名管道

2.1 pipe

pipefd为数组指针,传出的fd[0]为读管道,fd[1]为写管道
写端需要关闭读管道,也就是fd[0],读端需要 关闭写通道,也就是fd[1]

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

在这个例子中,创建管道1、管道2后,进行fork操作。在父进程中,关闭管道1的读管道,关闭管道2的写管道。在子进程中则相反,最终达到管道1,父写子读,管道2,父读子写的效果

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LINE 1024

int main(int argc, char **argv)
{
    int fd1[2], fd2[2];
    pid_t pid;
    int num;
    char buf[LINE];

    if (pipe(fd1) < 0) {
        printf("pipe fd1 error\n");
        return -1;
    }
    if (pipe(fd2) < 0) {
        printf("pipe fd2 error\n");
        return -1;
    }
    printf("prepare fork\n");
    pid = fork();
    if (pid < 0) {
        printf("fork error\n");
    } else if (pid > 0) {
        printf("prepare fork1\n");
        //父进程:返回子进程ID
        close(fd1[0]);  //管道1,父写子读。 管道2,父读子写
        close(fd2[1]); 
        char *str = "hello, this data is parent write by pipe1\n";
        write(fd1[1], str, strlen(str));

        num = read(fd2[0], buf, LINE);
        write(STDOUT_FILENO, buf, num);
    } else {
        printf("prepare fork2\n");
        //子进程:返回0
        close(fd1[1]);  //管道1,父写子读。 管道2,父读子写
        close(fd2[0]);
        num = read(fd1[0], buf, LINE);
        write(STDOUT_FILENO, buf, num);

        char *str2 = "hello, this data is child write by pipe2\n";
        write(fd2[1], str2, strlen(str2));
    }
    exit(0);
}

最终输出如下:
image.png

2.2 基于pipe的popen

常用的popen和pclose,其实就是基于无名管道进行的封装,感兴趣的可以看下源码,libc的各个版本有细微差异,但总体思路是一致的,然后工作中也经常用到popen封装的接口。相比system这个方式要更为安全,可以看另外一篇博客:

FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

在使用popen后,不用管道时要调用pclose将管道关闭

2.3 自己实现的基于popen读取命令输出函数

bool LinuxPopenExecCmd(std::string &strOutData, const char * pFormat, ...)
{
    char acBuff[128] ={0};

    va_list ap;
    int ret = -1;
    va_start(ap, pFormat);
    ret = vsprintf(acBuff, pFormat, ap);
    va_end(ap);

    FILE *pFile = popen(acBuff, "r");

    if (NULL == pFile)
    {
        return false;
    }

    char acValue[1024] = {0};
    while(fgets(acValue, sizeof(acValue), pFile) != NULL)
    {
        strOutData += acValue;
    }
    pclose(pFile);
    return true;
}
// 使用时直接这样使用即可,非常方便,并且支持格式化输入命令
std::string strValue;
LinuxPopenExecCmd(strValue, "ls -l"):
LinuxPopenExecCmd(strValue, "ls -l %s", "/tmp/"):
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值