在做软件开发时,为了实现一个复杂功能可能需要调用其他程序。具体功能在子进程中完成,父进程获取子进程的输出来判断结果。例如编程获得硬盘分区信息这个功能。如果自己从头开始写,只能这样实现:读取硬盘前几个扇区获得分区表,再分析表中的内容。如果直接使用Linux自带的lsblk程序就非常简单,因为lsblk可以输出json字符串,父进程获得后解析即可获得分区信息。
下面给出两种实现方案,第一种是用 Linux C 编程,另一种是用Qt框架编程。功能是:父进程创建子进程、等待子进程结束、获得子进程输出。
- Linux C
// get sub process's output in parent process using pipe redirection
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
#include <error.h>
#define BUFFSIZE 4000
int main()
{
int pipefd[2];
pid_t pid;
if (pipe(pipefd) != 0)
{
perror("cannot create pipe");
}
pid = fork();
if (pid == -1)
{
perror("cannot fork");
}
else if (pid == 0)
{
// child process
close(pipefd[0]);
int res = dup2(pipefd[1], STDOUT_FILENO);
if (res != -1)
execlp("lsblk", "lsblk", "--fs", "-o", "+MODEL,SIZE", "-J", NULL);
else
{
perror("cannot redirect");
exit(1);
}
}
close(pipefd[1]);
int status = -1;
waitpid(pid, &status, 0);
char buff[BUFFSIZE];
ssize_t count = 0;
count = read(pipefd[0], buff, BUFFSIZE - 1);
if (count > 0)
buff[count] = '\0';
else
perror("read error");
// is there left data ?
char test;
count = read(pipefd[0], &test, 1);
printf("%s\n", buff);
if (count == 1)
fprintf(stderr, "read incomplete data\n");
close(pipefd[0]);
return 0;
}
分析:
- 创建子进程使用 fork() execlp() 函数。
- 重定向子进程输出:pipe() dup2() 函数。先把子进程的stdout关闭,再把管道 write fd 复制到stdout对应的fd,最后execlp。子进程的输出内容写入管道中。
- 等待子进程结束:waitpid() 函数。
- 读取子进程输出:read() 函数,从管道中读取。
- Qt
QProcess lsblk;
lsblk.setProgram("lsblk");
lsblk.setArguments(QStringList() << "--fs" << "-o" << "+MODEL,SIZE" << "-J");
lsblk.start();
lsblk.waitForFinished(1000);
if (lsblk.exitCode() == 0)
qDebug() << lsblk.readAllStandardOutput();
else
qDebug() << lsblk.readAllStandardError();
分析:Qt使用面向对象的思想,把进程看做类。进程类QProcess继承了QIODevice类,这样处理输入输出十分方便。使用的时候创建进程对象lsblk,设置参数并执行,等待进程结束后可以直接获取输出内容。
这两种方法对比来看,Qt框架用起来更方便。QProcess封装了各种底层操作,同时提供强大的进程同步的函数,能轻松实现计时、读取、写入功能,还不需要担心缓冲区溢出的问题。
网友评论