Senden von ^ C an Python-Unterprozessobjekte unter Windows

Ich habe einen Testkabelbaum (geschrieben in Python), der das Programm unter Test (in C geschrieben) herunterfahren muss, indem es es sendet. Auf Unix,

proc.send_signal(signal.SIGINT) 

funktioniert perfekt. Unter Windows, das einen Fehler auslöst ("Signal 2 wird nicht unterstützt" oder so ähnlich). Ich benutze Python 2.7 für Windows, also habe ich den Eindruck, dass ich stattdessen stattfinden kann

  • Wie bekomme ich die Tiefe einer Jpg-Datei?
  • Erstellen eines benutzerdefinierten Benutzerregistrierungsformulars Django
  • SimpleHTTPServer und SocketServer
  • Windows Prozessmanagement mit Python
  • Wie berechnen Sie die Häufigkeit der Elemente für paarweise Vergleiche von Listen in Python?
  • Führen Sie mehrere scrapy Spinnen sofort mit scrapyd
  •  proc.send_signal(signal.CTRL_C_EVENT) 

    Aber das macht gar nichts Was muss ich tun? Dies ist der Code, der den Unterprozess erzeugt:

     # Windows needs an extra argument passed to subprocess.Popen, # but the constant isn't defined on Unix. try: kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP except AttributeError: pass proc = subprocess.Popen(argv, stdin=open(os.path.devnull, "r"), stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) 

  • Das Auslaufen des Gedächtnisses mit Python ElementTree
  • Firebase DB HTTP API Auth: Wann und wie kann man JWT Token aktualisieren?
  • Django: ImportError: Kein Modul namens? Z?
  • String Ersetzen für mehrere Zeilen in einem CSV
  • Installiere Paket, das setup_requires von lokalen Quellendistributionen hat
  • Unfähig, irgendwelche weißen Blobs zu erkennen - opencv python
  • 3 Solutions collect form web for “Senden von ^ C an Python-Unterprozessobjekte unter Windows”

    Es gibt eine Lösung, indem du einen Wrapper verwende (wie in dem Link Vinay angegeben), der in einem neuen Konsolenfenster mit dem Windows-Startbefehl gestartet wird .

    Code der Wrapper:

     #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) 

    Code des Programms fangen 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) 

    Starten Sie den Wrapper wie zB:

     PythonPrompt> import subprocess PythonPrompt> subprocess.Popen("start python wrapper.py", shell=True) 

    Sie müssen einen IPC-Code hinzufügen, der Ihnen erlaubt, den Wrapper zu steuern, der den Befehl os.kill (signal.CTRL_C_EVENT, 0) auslöst. Ich habe in diesem Antrag Steckdosen für diesen Zweck benutzt.

    Erläuterung:

    Vorinformation

    • send_signal(CTRL_C_EVENT) funktioniert nicht, weil CTRL_C_EVENT nur für os.kill . [REF1]
    • os.kill(CTRL_C_EVENT) sendet das Signal an alle Prozesse, die im aktuellen cmd-Fenster laufen [REF2]
    • Popen(..., creationflags=CREATE_NEW_PROCESS_GROUP) funktioniert nicht, da CTRL_C_EVENT für Prozessgruppen ignoriert wird. [REF2] Dies ist ein Fehler in der Pythonendokumentation [REF3]

    Implementierte Lösung

    1. Lassen Sie Ihr Programm in einem anderen cmd-Fenster mit dem Windows-Shell-Befehl starten .
    2. Fügen Sie einen CTRL-C-Anforderungs-Wrapper zwischen Ihrer Steuerungsanwendung und der Anwendung hinzu, die das CTRL-C-Signal erhalten soll. Der Wrapper läuft im selben cmd-Fenster wie die Anwendung, die das CTRL-C-Signal erhalten soll.
    3. Der Wrapper wird heruntergefahren und das Programm, das das CTRL-C-Signal erhalten soll, indem alle Prozesse im cmd-Fenster das CTRL_C_EVENT gesendet werden.
    4. Das Steuerprogramm sollte in der Lage sein, den Wrapper anzufordern, das CTRL-C-Signal zu senden. Dies kann durch IPC bedeutet, zB Sockel.

    Hilfreiche Beiträge waren:

    Ich musste das http vor den Links entfernen, weil ich ein neuer Benutzer bin und darf nicht mehr als zwei Links posten.

    Update: IPC-basierter CTRL-C-Wrapper

    Hier finden Sie ein selbstgeschriebenes Python-Modul, das eine CTRL-C-Verpackung mit einem Socket-basierten IPC bereitstellt. Die Syntax ähnelt dem Teilprozessmodul.

    Verwendung:

     >>> 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() 

    Code

     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) 

    Versuchen Sie, die GenerateConsoleCtrlEvent Funktion mit ctypes . Wenn Sie eine neue Prozessgruppe erstellen, sollte die Prozessgruppen-ID die gleiche sein wie die pid. Also so etwas wie

     import ctypes ctypes.windll.kernel32.GenerateConsoleCtrlEvent(0, proc.pid) # 0 => Ctrl-C 

    sollte arbeiten.

    Update: Du hast recht, ich habe diesen Teil des Details verpasst. Hier ist ein Beitrag, der eine mögliche Lösung vorschlägt, obwohl es ein bisschen kludgy ist. Weitere Details sind in dieser Antwort .

    Ich habe das schon versucht, aber aus irgendeinem Grund Strg + Break funktioniert, und Strg + C nicht. Also mit os.kill(signal.CTRL_C_EVENT, 0) scheitert, aber tun os.kill(signal.CTRL_C_EVENT, 1) funktioniert. Mir wurde gesagt, dass dies etwas mit dem schaffen Prozesseigentümer zu tun hat, der die einzige ist, die eine ctrl c übergeben kann? Ist das sinnvoll?

    Um zu klären, während man fio manuell in einem Befehlsfenster läuft, scheint es wie erwartet zu laufen. Mit dem STRG + BREAK Pausen, ohne das Protokoll zu speichern, wie erwartet und STRG + C beendet das Schreiben in die Datei auch wie erwartet. Das Problem scheint im Signal für den CTRL_C_EVENT zu sein.

    Es scheint fast ein Fehler in Python zu sein, aber vielleicht ein Fehler in Windows sein. Auch eine andere Sache, ich hatte eine Cygwin-Version läuft und das Senden der Strg + c in Python dort auch gearbeitet, aber dann wieder sind wir nicht wirklich native Fenster dort laufen.

    Beispiel:

     import subprocess, time, signal, sys, os command = '"C:\\Program Files\\fio\\fio.exe" --rw=randrw --bs=1M --numjobs=8 --iodepth=64 --direct=1 ' \ '--sync=0 --ioengine=windowsaio --name=test --loops=10000 ' \ '--size=99901800 --rwmixwrite=100 --do_verify=0 --filename=I\\:\\test ' \ '--thread --output=C:\\output.txt' def signal_handler(signal, frame): time.sleep(1) print 'Ctrl+C received in wrapper.py' signal.signal(signal.SIGINT, signal_handler) print 'command Starting' subprocess.Popen(command) print 'command started' time.sleep(15) print 'Timeout Completed' os.kill(signal.CTRL_C_EVENT, 0) 
    Python ist die beste Programmiersprache der Welt.