发送信号/事件到独立进程

时间:2018-11-13 14:05:49

标签: python python-3.x windows

所以我有一个完全独立的过程,带有已知的PID。

我想从另一个不相关的进程向它发送某种中断,以使其“正常”退出。

linux 中,它看起来像这样:

first_script:

def signal_handler(signum, stack):
    print("SIGNAL RECIEVED")
    sys.exit()

signal.signal(signal.SIGUSR1, handle_signal)
while True:
    print("Im working")

第二个脚本:

known_pid = input("Enter pid")
os.kill(int(known_pid), signal.SIGUSR1)

由于Windows不支持这种方式的信号传输,因此它显然行不通,但我找不到其他简单的解决方案(经过广泛的研究)。

2 个答案:

答案 0 :(得分:1)

考虑使用psutil,我认为它非常适合您的情况。

document中所述,以下代码可以完成您想要的操作。尽管您可能不需要find_procs_by_name的一部分。

import os
import signal
import psutil

def find_procs_by_name(name):
    "Return a list of processes matching 'name'."
    ls = []
    for p in psutil.process_iter(attrs=["name", "exe", "cmdline"]):
        if name == p.info['name'] or \
                p.info['exe'] and os.path.basename(p.info['exe']) == name or \
                p.info['cmdline'] and p.info['cmdline'][0] == name:
            ls.append(p)
    return ls

def kill_proc_tree(pid, sig=signal.SIGTERM, include_parent=True,
                   timeout=None, on_terminate=None):
    """Kill a process tree (including grandchildren) with signal
    "sig" and return a (gone, still_alive) tuple.
    "on_terminate", if specified, is a callabck function which is
    called as soon as a child terminates.
    """
    if pid == os.getpid():
        raise RuntimeError("I refuse to kill myself")
    parent = psutil.Process(pid)
    children = parent.children(recursive=True)
    if include_parent:
        children.append(parent)
    for p in children:
        p.send_signal(sig)
    gone, alive = psutil.wait_procs(children, timeout=timeout,
                                    callback=on_terminate)
    return (gone, alive)

pid = find_procs_by_name('POWERPNT.EXE')[0].pid
print(find_procs_by_name('POWERPNT.EXE')[0].pid)
kill_proc_tree(pid)

答案 1 :(得分:1)

您可以使用pywin32提供的Windows API或使用套接字对其进行入侵。

套接字解决方案又快又脏:

# waiting process

import socket
import select
import time

server = socket.socket()
server.bind(('localhost', 1337))
server.listen(5)

# this select() call returns ([server], [], [])
# if server is readable, else ([], [], []), and waits 0 seconds
while not select.select([server], [], [], 0)[0]:
    print('working')
    time.sleep(0.5)


# parent process

import socket    
socket.create_connection(('localhost', 1337))

Windows解决方案更长但更准确地表示了问题:

# waiting process

import time
import win32event

# open an existing event by name with the required access
# (didn't work for me with EVENT_MODIFY_STATE, got "Access denied" error)
event = win32event.OpenEvent(win32event.EVENT_ALL_ACCESS, 0, "MY_NAME")

# Wait 0 seconds on the event. If event has been set, WAIT_OBJECT_0 is returned
while win32event.WaitForSingleObject(event, 0) != win32event.WAIT_OBJECT_0:
    print('working')
    time.sleep(0.5)


# parent process
# note that it should be run first

import win32event
import time

# create event by name
event = win32event.CreateEvent(
    None,       # not inherited by child processes
    False,      # auto-reset the event after it is set
    False,      # created unset
    "MY_NAME",  # event name
)
time.sleep(5)  # wait for waiting process to start
win32event.SetEvent(event)

这只是最小的POC。建议您阅读有关event objects的信息,以找到适合您的确切解决方案。