在 kill() 之后从子进程中检索一个值

Retrieve a value from subprocess after kill()

这是一个有点奇怪的项目,我试图使用一个子流程来跟踪我按下的键数以衡量我的工作效率。

目前我使用 Amazon Dash 按钮启动子进程,然后在第二次按下时终止进程。

def start_keylogger():
    global process
    process = subprocess.Popen(["sudo", "python", "test.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

def stop_keylogger():
    os.killpg(process.pid, signal.SIGUSR1)
    process.wait()
    key_press_count = process.stdout.read()
    return key_press_count

从那里我的键盘记录器还没有充实,但我想我想使用 sys.exit()exit() 到 return 按键次数。

def exit_and_return_counter():
    sys.stdout.write(current_keypress_counter)
    exit()

if __name__ == '__main__':
    signal.signal(signal.SIGUSR1, exit_and_return_counter)
    try:
        while 1:
           main_loop()
    except KeyboardInterrupt:
        sys.exit()

最初我尝试使用 process.returncode,但它只 returned 1,我假设成功退出代码。而且我不能使用 stdout, stderr = process.communicate() 除非我想在第二次按下亚马逊按钮后保持键盘记录器一会儿。

简直运行 process.wait()os.killpg(process.pid, signal.SIGUSR1) 之后。这等待进程结束和 returns 状态代码。因为你刚刚杀死它,所以它不会阻塞太久。捕获 USR1 信号并使用 sys.exit 更改从 child 返回的代码应该有效。

即使在 child 被杀死后,您也应该能够使用 process.stdout.read() 读取标准输出,因为为 inter-process 通信创建的管道至少与Popen object process 存在。

虽然不是一个优雅的答案,但使用 process.send_signal(signal.SIGUSR1) 有效(如 @cg909 所述)。在停止方法中我们有:

def stop_keylogger():
    process.send_signal(signal.SIGUSR1)
    process.wait()
    return process.stderr.read()

然后在键盘记录器中处理信号:

def exit_and_return_counter(*args):
    sys.stdout.write('%s'%counter)
    exit()

if __name__ == '__main__':
    signal.signal(signal.SIGUSR1, exit_and_return_counter)
    try:
        while 1:
            main_loop()
    except KeyboardInterrupt:
        sys.exit()

您可以使用 SIGINT 信号(Ctrl+C 在终端中)向进程发出信号以打印统计信息和出口。您可以使用 KeyboardInterrupt 异常处理程序处理 SIGINT

#!/usr/bin/env python
#file: keylogger.py
import random
import time

counter = 0

def mainloop()
    global counter
    while True:
        counter += 1
        time.sleep(random.random())

if __name__ == '__main__':
    try:
        mainloop()
    except KeyboardInterrupt: # on SIGINT
        print(counter)

这是对应的控制器:

#!/usr/bin/env python3
import os
import signal
from subprocess import Popen, PIPE, DEVNULL

process = None

def start_keylogger():
    global process
    stop_keylogger(expect_process_running=False)
    process = Popen(["python", "-m", "keylogger"], stdout=PIPE, stderr=DEVNULL,
                    preexec_fn=os.setpgrp)

def stop_keylogger(expect_process_running=True):
    global process
    if process is not None and process.poll() is None:
        os.killpg(process.pid, signal.SIGINT)
        counter = int(process.communicate()[0])
        process = None
        return counter
    if expect_process_running:
        raise RuntimeError('keylogger is not running')

当您在终端中 运行 keylogger.py 时(对于 testing/debugging),您可以通过按 Ctrl 来模拟发送 SIGINT +C.

preexec_fn=os.setpgrp 创建一个单独的进程组。 os.killpg() 向它发送信号。如果您的 keylogger.py 在不需要 preexec_fn=os.setpgrp 时没有生成自己的子进程,并且调用 process.send_signal(signal.SIGINT) 而不是 os.killpg() 就足够了。

考虑