在node.js中生成并杀死进程


70

我试图在javascript中生成一个进程,并在一段时间后将其杀死(出于测试目的)。

最后,该过程将是一个无限循环,我需要在指定的时间使用不同的参数重新启动,因此我认为生成该过程并杀死它是执行此操作的最佳方法。

我的测试代码是:

var spawn=require('child_process').spawn
, child=null;

child=spawn('omxplayer', ['test.mp4'], function(){console.log('end');}, {timeout:6000});
console.log('Timeout');
setTimeout(function(){
    console.log('kill');
    child.kill();
}, 1200);

child.stdout.on('data', function(data){
    console.log('stdout:'+data);
});

child.stderr.on('data', function(data){
    console.log('stderr:'+data);
});

child.stdin.on('data', function(data){
    console.log('stdin:'+data);
});

结果是:

#~$ node test.js
Timeout
kill

但是我仍然需要发送ctrl + C来结束程序。我想念什么?

在Raspbian的节点0.10.17上,omxplayer是二进制文件(视频播放器)。

我试过了:

  • 已添加chmod +x到应用程序。
  • 以root身份启动。
  • 子进程的标准输入暂停。在kill命令中使用所有与终止相关的信号。

ps在应用运行时,我还启动了一个命令:

2145    bash
2174    node
2175    omxplayer
2176    omxplayer.bin
2177    ps

所以omxplayer是一个包装器,结束时谁不会杀死它的子进程,有没有办法获取被包装进程的pid?

仍然咬灰尘,尝试了这个:

spawn('kill', ['-QUIT', '-$(ps opgid= '+child.pid+')']);

我以为会杀死omxplayer的所有子级,所以我不知道使用这样的spawn是错误的还是代码不起作用。

我所做的最后一个编辑是一个很好的答案,但必须进行一些编辑。

我创建了一个sh文件(具有执行权限),如下所示:

PID=$1
PGID=$(ps opgid= "$PID")
kill -QUIT -"$PGID"

我是这样开始的:

execF('kill.sh', [child.pid], function(){
    console.log('killed');
});

代替child.kill

我不确定这是否是最好的方法,也不确定代码是否干净,但是确实有效。

我会接受任何更干净或更有效的答案,而不必执行文件。


Raspbian上的Raspberry Pi(不确定版本),节点0.10.2。我将尝试更新节点。
2013年

1
也许有些特权。尝试运行具有root用户访问权限的节点脚本。
Krasimir 2013年

将节点更新为0.10.17,并尝试以root用户身份运行,但均无法正常工作。
2013年

1
难道是与OMX的问题。尝试更新它。
user568109 2013年

3
我猜想omxplayer可执行文件是将视频输出到屏幕的进程的包装,并且它不会关闭它产生的视频进程。
user568109 2013年

Answers:


57

参考此讨论

一旦开始在stdin上侦听数据,node将等待在stdin上的输入,直到被告知不这样做为止。当用户按下ctrl-d(表示输入结束)或程序调用stdin.pause()时,节点将停止等待stdin。

除非没有任何事情要做或等待,否则节点程序不会退出。发生的是,它在标准输入上等待,因此从不退出。

尝试将setTimeout回调更改为

console.log('kill');
child.stdin.pause();
child.kill();

我希望它能起作用。


也尝试过这个,并评论了所有“关于数据”,我仍然需要等待视频的结尾。
2013年

2
尝试child.kill('SIGKILL'),看看是否可行。child.kill()发送SIGHUP,它只是告诉控制终端已关闭或控制进程已关闭。我的假设是SIGKILL肯定会杀死它。
robinkc 2013年

1
尝试过SIGHUP,SIGTERM和SIGKILL,消息kill被打印出来,但是视频仍然可以播放。
2013年

尝试过SIGKILL,SIGTERM,SIGABRT,SIGHUP,SIGINT和SIGQUIT,它们都不做任何事情,甚至一个接一个地发射。
2013年

当我尝试生成诸如pidgin之类的其他命令的子代时,代码工作得很好。但这不是用omxplayer吗?嗯
robinkc 2013年

40

有一个非常简洁的npm软件包tree-kill,可以非常轻松有效地完成此操作。它会杀死子进程,以及该子进程可能已启动的所有子进程。

var kill  = require('tree-kill');
const spawn = require('child_process').spawn;

var scriptArgs = ['myScript.sh', 'arg1', 'arg2', 'youGetThePoint'];
var child = spawn('sh', scriptArgs);

// some code to identify when you want to kill the process. Could be
// a button on the client-side??
button.on('someEvent', function(){
    // where the killing happens
    kill(child.pid);
});

谢谢。这对我有用,似乎是一个不错的选择。
TechnoTim

这为我工作,而child.kill()没有。使用NodeJS v14.15.1,Windows 10
萝卜

9

对于omxplayer,我遇到了与您完全相同的问题,此博客文章中的解决方案对我有用。

var psTree = require('ps-tree');

var kill = function (pid, signal, callback) {
    signal   = signal || 'SIGKILL';
    callback = callback || function () {};
    var killTree = true;
    if(killTree) {
        psTree(pid, function (err, children) {
            [pid].concat(
                children.map(function (p) {
                    return p.PID;
                })
            ).forEach(function (tpid) {
                try { process.kill(tpid, signal) }
                catch (ex) { }
            });
            callback();
        });
    } else {
        try { process.kill(pid, signal) }
        catch (ex) { }
        callback();
    }
};

// elsewhere in code
kill(child.pid);

5

您为什么不只在stdin管道中发送“ q”值?它杀死了omxplayer进程。


你能解释一下吗?
chovy

这是omxplayer的自然行为。当您在shell中启动它时,进程正在等待诸如“ q”之类的快捷方式,这些快捷方式将关闭程序。
Superdrac

这是非常干净的解决方案,也适用于其他程序。f.stdin.write(“ q \ n”); 因为需要某种输入。
Evil

1

您已经生成了一个成功杀死的子进程。但是,您的主线程仍在执行,这就是为什么必须按Ctrl + C的原因。


2
如果只是主进程仍在运行,我会很高兴,但是子进程显然仍在运行,因为视频仍然可以播放,直到我发送ctrl + C。
2013年

1

最后,我找到了没有脚本的方法:

exec('pkill omxplayer', function(err, stdout, stderr){
    if (stdout){console.log('stdout:'+stdout);}
    if (stderr){console.log('stderr:'+stderr);}
    if (err){throw err;}
    //...
}

0

child_process.execFile()这里尝试使用方法。

child_process.execFile()函数与child_process.exec()类似,不同之处在于它不生成shell。而是直接将指定的可执行文件作为新进程生成,从而使其效率比child_process.exec()略高。

在我的情况下有效。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.