杀死以 popen 启动的进程

发布于 2024-07-13 11:28:26 字数 106 浏览 9 评论 0原文

使用popen打开一个进程的管道后,有没有办法杀死已经启动的进程? (使用 pclose 不是我想要的,因为它将等待进程完成,但我需要杀死它。)

After opening a pipe to a process with popen, is there a way to kill the process that has been started? (Using pclose is not what I want because that will wait for the process to finish, but I need to kill it.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

墨小墨 2024-07-20 11:28:26

不要使用 popen(),编写您自己的包装器来执行您想要的操作。

fork() 相当简单,然后替换 stdin & 标准输出
使用 dup2(),然后对您的孩子调用 exec()

这样,您的父级将拥有准确的子级 PID,您可以使用
kill() 对此。

谷歌搜索“popen2()实现”的一些示例代码
如何实现popen()正在做的事情。 只有十几行
长的。 取自 dzone.com 我们可以看到
一个如下所示的示例:

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execl("/bin/sh", "sh", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

注意:似乎 popen2() 就是您想要的,但我的发行版似乎没有提供此方法。

Don't use popen(), write your own wrapper that does what you'd like.

It's fairly straightforward to fork(), and then replace stdin & stdout
by using dup2(), and then calling exec() on your child.

That way, your parent will have the exact child PID, and you can use
kill() on that.

Google search for "popen2() implementation" for some sample code on
how to implement what popen() is doing. It's only a dozen or so lines
long. Taken from dzone.com we can see
an example that looks like this:

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execl("/bin/sh", "sh", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

NB: Seems like popen2() is what you want, but my distribution doesn't seem to come with this method.

凉城 2024-07-20 11:28:26

这是 popen2 的改进版本(感谢 Sergey L.)。 slacy发布的版本并不返回popen2中创建的进程的PID,而是返回分配给sh的PID。

pid_t popen2(const char **command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execvp(*command, command);
        perror("execvp");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

新版本将被调用

char *command[] = {"program", "arg1", "arg2", ..., NULL};

Here is an improved version of popen2 (credit is due to Sergey L.). The version posted by slacy does not return the PID of the process created in popen2, but the PID assigned to sh.

pid_t popen2(const char **command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execvp(*command, command);
        perror("execvp");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

The new version is to be called with

char *command[] = {"program", "arg1", "arg2", ..., NULL};
伤痕我心 2024-07-20 11:28:26

popen 实际上并没有启动一个线程,而是派生了一个进程。 当我查看定义时,似乎没有一种简单的方法可以获取该进程的 PID 并杀死它。 可能有一些困难的方法,比如检查进程树,但我想你最好使用 Pipe、fork 和 exec 函数来模仿 popen 的行为。 然后你可以使用从 fork() 获得的 PID 来终止子进程。

popen does not actually start a thread, but rather forks a process. As I look at the definition, it doesn't look like there is an easy way to get PID of that process and kill it. There might be difficult ways like examining process tree, but i guess you'd be better off with using pipe, fork and exec functions to mimic behaviour of popen. Then you can use PID you get from fork() to kill the child process.

东走西顾 2024-07-20 11:28:26

实际上,如果进程正在执行 I/O(应该如此,否则为什么使用 popen 而不是 system(3)?),则 pclose应该在下次尝试读取或写入时用 SIGPIPE 敲击它,并且它应该很好地倒下:-)

Actually if the process is doing I/O (which it should be, otherwise why popen instead of system(3)?), then pclose should whack it with a SIGPIPE the next time it tries to read or write, and it should fall over nicely :-)

書生途 2024-07-20 11:28:26

我遵循 @slacy 创建函数 popen2 的想法。
但发现问题是,当子进程死亡时,仍然读取文件描述符 outfp 的父进程不会从函数返回。

这可以通过在父进程上添加关闭未使用管道来解决。

close(p_stdin[READ]);
close(p_stdout[WRITE]);

我们可以使用 bash 作为 shell 来获取新进程的正确 pid。

execl("/bin/bash", "bash", "-c", command, NULL);

当子进程死亡时,函数popen2的调用者应该通过调用pclose2来收集子进程的状态。 如果我们不收集该状态,子进程在终止时可能是僵尸进程。

这是经过测试并按预期工作的完整代码。

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        dup2(p_stdin[READ], STDIN_FILENO);
        dup2(p_stdout[WRITE], STDOUT_FILENO);

     //close unuse descriptors on child process.
     close(p_stdin[READ]);
     close(p_stdin[WRITE]);
     close(p_stdout[READ]);
     close(p_stdout[WRITE]);

        //can change to any exec* function family.
        execl("/bin/bash", "bash", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    // close unused descriptors on parent process.
    close(p_stdin[READ]);
    close(p_stdout[WRITE]);

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

int
pclose2(pid_t pid) {
    int internal_stat;
    waitpid(pid, &internal_stat, 0);
    return WEXITSTATUS(internal_stat);
}

I have follow idea of @slacy that create function popen2.
But found problem when child process is die, parent process that still read file descripter outfp not return from function.

That could fix by add close unuse pipe on parent process.

close(p_stdin[READ]);
close(p_stdout[WRITE]);

We can get correct pid of new process by using bash as shell.

execl("/bin/bash", "bash", "-c", command, NULL);

When child process die the caller of function popen2 should collect status of child process by call pclose2. if we don't collect that status child process could be zombie process when it terminate.

This is the full code that tested and work as expect.

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        dup2(p_stdin[READ], STDIN_FILENO);
        dup2(p_stdout[WRITE], STDOUT_FILENO);

     //close unuse descriptors on child process.
     close(p_stdin[READ]);
     close(p_stdin[WRITE]);
     close(p_stdout[READ]);
     close(p_stdout[WRITE]);

        //can change to any exec* function family.
        execl("/bin/bash", "bash", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    // close unused descriptors on parent process.
    close(p_stdin[READ]);
    close(p_stdout[WRITE]);

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

int
pclose2(pid_t pid) {
    int internal_stat;
    waitpid(pid, &internal_stat, 0);
    return WEXITSTATUS(internal_stat);
}
我做我的改变 2024-07-20 11:28:26

最明显的方法是 system("pkill process_name");

显然,如果您有多个正在运行的进程实例,那么这是有问题的。

The obvious way is system("pkill process_name");

Clearly this is problematic if you have more than one instance of the process running.

尘世孤行 2024-07-20 11:28:26

我在 python 中做了类似的事情,你可以杀死一个子进程以及为此分叉的任何子进程。 实际上与 slacy 的解决方案类似。
http://www.pixelbeat.org/libs/subProcess.py

I did something similar in python, where you could kill a subprocess and any subprocesses forked for that. It's similar to slacy's solution actually.
http://www.pixelbeat.org/libs/subProcess.py

看春风乍起 2024-07-20 11:28:26

我只是将(bash)脚本放入第一行:

echo PID $

然后我读取 pid,并用它来执行以下操作:
杀死(pid,9)

I simply put in the (bash) script, in the first line:

echo PID $

then I read the pid, and use it to do a :
kill(pid,9)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文