C++ 从popen那里得到PID
我有一个程序,它使用popen打开并读取shell命令的输出。问题是,据我所知,没有简单的方法可以获得正在运行的进程的PID,因此,如果它卡住了,您无法杀死它。因此,问题是,如何从使用popen打开的进程中检索PID?我提出的解决方案和普遍共识是创建一个新的popen函数,允许我检索PID。因为我找不到一个简单的例子,所以我想发布我的实现,希望它能帮助其他人。欢迎反馈和替代解决方案C++ 从popen那里得到PID,c++,c,popen,pid,C++,C,Popen,Pid,我有一个程序,它使用popen打开并读取shell命令的输出。问题是,据我所知,没有简单的方法可以获得正在运行的进程的PID,因此,如果它卡住了,您无法杀死它。因此,问题是,如何从使用popen打开的进程中检索PID?我提出的解决方案和普遍共识是创建一个新的popen函数,允许我检索PID。因为我找不到一个简单的例子,所以我想发布我的实现,希望它能帮助其他人。欢迎反馈和替代解决方案 #include <unistd.h> #include <stdlib.h> #incl
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <string>
#include <sstream>
using namespace std;
#define READ 0
#define WRITE 1
FILE * popen2(string command, string type, int & pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == "r")
{
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else
{
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[READ], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
exit(0);
}
else
{
if (type == "r")
{
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
}
}
pid = child_pid;
if (type == "r")
{
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
int main()
{
int pid;
string command = "ping 8.8.8.8";
FILE * fp = popen2(command, "r", pid);
char command_out[100] = {0};
stringstream output;
//Using read() so that I have the option of using select() if I want non-blocking flow
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0)
{
output << string(command_out);
kill(-pid, 9);
memset(&command_out, 0, sizeof(command_out));
}
string token;
while (getline(output, token, '\n'))
printf("OUT: %s\n", token.c_str());
pclose2(fp, pid);
return 0;
}
澄清
我试图使用@Gillespie的答案定义的函数,但发现C/C++程序中的pid与终端命令pgrep返回的pid不同,并且查看ps-aux | grep myNameProc的输出,C程序的进程似乎再次分叉
我想是因为execl/bin/sh,/bin/sh,-c,command.c_str,NULL;实际上相当于/bin/sh cmd字符串。因此,基本上,C或C++程序的子进程正在创建一个新的进程,它在/Real/SH您的RealPoal过程中,其中RealRealPosio是命令字符串中指定的一个进程。
我解决了以下问题:execlcommand.c_str,command.c_str,char*NULL;。但是,正如@Gillespie在前面的评论中所指定的,通过这种方式,您将无法向流程传递参数
C执行
根据我的需要,我重新调整了@Gillespie的函数,以包括上述修改,并使用C编程语言:
FILE * custom_popen(char* command, char type, pid_t* pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == 'r')
{
close(fd[0]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[1], 1); //Redirect stdout to pipe
}
else
{
close(fd[1]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[0], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl(command, command, (char*)NULL);
exit(0);
}
else
{
printf("child pid %d\n", child_pid);
if (type == 'r')
{
close(fd[1]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[0]); //Close the READ end of the pipe since parent's fd is write-only
}
}
*pid = child_pid;
if (type == 'r')
{
return fdopen(fd[0], "r");
}
return fdopen(fd[1], "w");
}
int custom_pclose(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
您可以使用fdopenGreat建议返回一个文件*,因为原始popen也会返回文件*。我更新了我的代码。你可以在一些自由软件libc中研究popen的实现,例如,因为你很好奇,glibc将pid保存在文件结构中:在子进程中的exec调用失败后调用exit是个坏主意。这将刷新从父进程复制到父进程流的所有缓冲数据,并调用父进程注册的所有退出处理程序。在C++过程中,它也会导致所有静态析构函数运行。对exit的调用应替换为_exit。您是想要生成的/bin/sh进程的PID,还是由于向/bin/sh传递任何命令行而生成的其他几个进程之一?在一般情况下,这里不一定只有一个PID,这可能至少是它不可用的部分原因…是的,/bin/sh应该足够了-我真的只是想要一些可以让我终止进程的东西,比如iperf服务器模式。为什么不使用systemkillall-9 iperf?这样做的缺点是什么?当做ugesh@UgeshReddykillall-9IPERF将杀死系统范围内的所有iperf进程,即使它与我的特定应用程序无关。另外,我需要杀死的不仅仅是iperf,还有ping或curl等命令。请注意,您可以非常轻松地添加对参数的支持,您必须在空格处分解字符串,或者将另一个参数传递给带有argv数组的函数。然后您可以将其传递给execv,以便进行一些小的更改。此外,如果exec*函数无法启动命令,它们可能会返回。