Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在kill()之后从子流程检索值_Python_Subprocess_Popen_Sys - Fatal编程技术网

Python 在kill()之后从子流程检索值

Python 在kill()之后从子流程检索值,python,subprocess,popen,sys,Python,Subprocess,Popen,Sys,所以这是一个有点奇怪的项目,我试图使用一个子流程来跟踪我按下的键的数量来衡量我的生产力 目前,我使用Amazon Dash按钮启动子流程,然后在第二次按下时终止该流程 def start_keylogger(): global process process = subprocess.Popen(["sudo", "python", "test.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) def stop_keyl

所以这是一个有点奇怪的项目,我试图使用一个子流程来跟踪我按下的键的数量来衡量我的生产力

目前,我使用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()
来返回按键次数

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
,但它只返回
1
,我假设退出代码成功。我不能使用stdout,stderr=process.communicate(),除非我想在第二次按下Amazon按钮后让键盘记录器保持一段时间

只需运行
process.wait()
os.killpg(process.pid,signal.SIGUSR1)
之后。这将等待进程结束并返回状态代码。因为你刚才杀了它,它不会阻塞很长时间。捕捉USR1信号并使用
sys.exit
更改从子级返回的代码应该可以工作


即使在孩子被杀死后,您也应该能够使用
process.stdout.read()
读取stdout,因为为进程间通信创建的管道将至少在Popen对象
process
存在的时间内有效。

虽然不是一个优雅的答案,但使用
process.send\u 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
signal(终端中的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
时,按Ctrl+C可以模拟发送
SIGINT

preexec\u fn=os.setpgrp
创建一个单独的进程组。
os.killpg()
向它发送信号。如果您的
keylogger.py
没有生成自己的子进程,那么当
preexec\u fn=os.setpgrp
是不必要的,并且调用
进程就足够了。send\u signal(signal.SIGINT)
而不是
os.killpg()


请考虑。

只有当进程正常退出时,才能使用
exit(code)获取返回代码
。当您杀死它时,进程由于信号而退出,并且无法发送退出代码。顺便说一句,在Unix上,最大可能的退出代码是
255
。因此,如果您可能键入的密钥超过了那么多,那么您的技术就没有用。@Barmar:即使进程被杀死,您也可以得到返回代码(
rc=process.wait())
--可能是
-9
(对应于
SIGKILL
)。虽然OP的代码还有其他问题。代码中存在多个问题,例如:(1)如果需要
子流程,导入
调用
是毫无意义的。Popen
(2)(3)
全局
内部
停止键记录器()
是不必要的(没有赋值)(4)
process.kill()
不会杀死整个进程树,请参阅(5)KeyboardInterrupt不会捕获SIGKILL(6),正如@Barmar所说:退出状态范围可能太大small@J.F.Sebastian但是不能使用
sys.exit()返回特定代码
如果进程被终止。因此等待进程显然是一个问题,但我没有从
退出(当前按键次数)
中得到任何回报。我假设我一定没有处理
信号.SIGUSR1
对。请澄清,
进程.stdout.read()
没有返回任何内容,并且
进程。returncode
正在尝试从Popen调用中删除
stderr=subprocess.PIPE
。然后您可以看到子进程正在抛出的Python异常。:-)我发现了以下问题:信号回调必须接受两个参数:信号号和堆栈帧,因此:
exit_和_return_计数器(signo,frame):
sys.stdout.write()
需要字符串,所以使用sys.stdout.write(str(当前的按键计数器))。同样在我的计算机上
os.killpg()
不起作用。
进程。发送信号(signal.SIGUSR1)
对我起作用了。太棒了,是的,当用
进程发送时,我能够处理
SIGUSR1
。发送信号(signal.SIGUSR1)
。我把我的更改放在下面的答案中。谢谢@cg909的帮助