Python 在kill()之后从子流程检索值
所以这是一个有点奇怪的项目,我试图使用一个子流程来跟踪我按下的键的数量来衡量我的生产力 目前,我使用Amazon Dash按钮启动子流程,然后在第二次按下时终止该流程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
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的帮助