Hay una solución mediante el uso de un contenedor (como se describe en el enlace Vinay proporcionado) que se inicia en una nueva ventana de la consola con el comando start de Windows.
Código de la envoltura:
#wrapper.py
import subprocess, time, signal, sys, os
def signal_handler(signal, frame):
time.sleep(1)
print 'Ctrl+C received in wrapper.py'
signal.signal(signal.SIGINT, signal_handler)
print "wrapper.py started"
subprocess.Popen("python demo.py")
time.sleep(3) #Replace with your IPC code here, which waits on a fire CTRL-C request
os.kill(signal.CTRL_C_EVENT, 0)
Código del programa de captura CTRL-C:
#demo.py
import signal, sys, time
def signal_handler(signal, frame):
print 'Ctrl+C received in demo.py'
time.sleep(1)
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print 'demo.py started'
#signal.pause() # does not work under Windows
while(True):
time.sleep(1)
lanzamiento del envoltorio, como por ejemplo:
PythonPrompt> import subprocess
PythonPrompt> subprocess.Popen("start python wrapper.py", shell=True)
es necesario agregar algunos Código IPC que le permite controlar el contenedor que activa el comando os.kill (signal.CTRL_C_EVENT, 0). Utilicé enchufes para este propósito en mi aplicación.
Explicación:
información previa
send_signal(CTRL_C_EVENT)
no funciona porque CTRL_C_EVENT
es sólo para os.kill
. [REF1]
os.kill(CTRL_C_EVENT)
envía la señal a todos los procesos que se ejecutan en la ventana de cmd actual [REF2]
Popen(..., creationflags=CREATE_NEW_PROCESS_GROUP)
no funciona porque CTRL_C_EVENT
se ignora para los grupos de procesos.[REF2] trata de un error en la documentación de Python [REF3]
solución implementada
- Deje que su ejecución del programa en una ventana cmd diferente con el comando shell de Windows inicia .
- Agregue un contenedor de solicitud CTRL-C entre su aplicación de control y la aplicación que debería recibir la señal CTRL-C. El contenedor se ejecutará en la misma ventana de cmd que la aplicación que debería recibir la señal CTRL-C.
- El contenedor se apagará y el programa que recibirá la señal CTRL-C enviará todos los procesos en la ventana del cmd CTRL_C_EVENT.
- El programa de control debería poder solicitar al envoltorio que envíe la señal CTRL-C. Esto podría implementarse a través de los medios de IPC, p. enchufes
mensajes útiles fueron:
tuve que quitar el http frente a los enlaces porque soy un nuevo usuario y no se le permite colocar más de dos enlaces.
Actualización: Contenedor CTRL-C basado en IPC
Aquí puede encontrar un módulo python auto-escrito que proporciona un envoltorio CTRL-C que incluye un IPC basado en socket. La sintaxis es bastante similar al módulo de subproceso.
Uso:
>>> import winctrlc
>>> p1 = winctrlc.Popen("python demo.py")
>>> p2 = winctrlc.Popen("python demo.py")
>>> p3 = winctrlc.Popen("python demo.py")
>>> p2.send_ctrl_c()
>>> p1.send_ctrl_c()
>>> p3.send_ctrl_c()
Código
import socket
import subprocess
import time
import random
import signal, os, sys
class Popen:
_port = random.randint(10000, 50000)
_connection = ''
def _start_ctrl_c_wrapper(self, cmd):
cmd_str = "start \"\" python winctrlc.py "+"\""+cmd+"\""+" "+str(self._port)
subprocess.Popen(cmd_str, shell=True)
def _create_connection(self):
self._connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._connection.connect(('localhost', self._port))
def send_ctrl_c(self):
self._connection.send(Wrapper.TERMINATION_REQ)
self._connection.close()
def __init__(self, cmd):
self._start_ctrl_c_wrapper(cmd)
self._create_connection()
class Wrapper:
TERMINATION_REQ = "Terminate with CTRL-C"
def _create_connection(self, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', port))
s.listen(1)
conn, addr = s.accept()
return conn
def _wait_on_ctrl_c_request(self, conn):
while True:
data = conn.recv(1024)
if data == self.TERMINATION_REQ:
ctrl_c_received = True
break
else:
ctrl_c_received = False
return ctrl_c_received
def _cleanup_and_fire_ctrl_c(self, conn):
conn.close()
os.kill(signal.CTRL_C_EVENT, 0)
def _signal_handler(self, signal, frame):
time.sleep(1)
sys.exit(0)
def __init__(self, cmd, port):
signal.signal(signal.SIGINT, self._signal_handler)
subprocess.Popen(cmd)
conn = self._create_connection(port)
ctrl_c_req_received = self._wait_on_ctrl_c_request(conn)
if ctrl_c_req_received:
self._cleanup_and_fire_ctrl_c(conn)
else:
sys.exit(0)
if __name__ == "__main__":
command_string = sys.argv[1]
port_no = int(sys.argv[2])
Wrapper(command_string, port_no)
Esta podría ser la única manera - http://code.activestate.com/recipes/347462-terminating-a-subprocess-on-windows/ con win32api OH o ctypes. – arunkumar
'subprocess.kill' llamará' TerminateProcess' para mí, pero eso no genera^C. Específicamente necesito fingir el comportamiento de escribir^C en la consola. – zwol
intente esto - http://www.rutherfurd.net/python/sendkeys/. aparentemente SendKeys.SendKeys ("^ c") debería hacerlo. – arunkumar