Python-ROHR zu popen stdin
Ich bin versucht, etwas sehr ähnlich zu Echtzeit-Teilprozess.Popen, die über stdout und PIPE
Ich will jedoch zum senden von input für den Laufenden Prozess als gut.
Wenn ich einen Prozess starten, in einem separaten thread mit
process = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Kann ich senden Eingabe mit dem terminal.
Wie würde ich das senden von Eingaben von einer anderen Quelle, wie separate Funktion nicht in den thread?
Kann ich nicht verwenden Popen.communicate
wie der laufende Prozess wird nie abgeschlossen, so wie ich bin versucht Echtzeit-Interaktion mit dem Programm.
Vielen Dank im Voraus.
Hier ist mein vollständiger code, ich bin auf der Suche zum Eingang geschickt, um die subprocoess Prozess, wenn die senden-Schaltfläche geklickt wird.
from Tkinter import *`
from ttk import *`
import subprocess
from threading import Thread
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Test Client")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
#Label, doesnt change
lbl = Label(self, text="Client:")
lbl.grid(row=0, column=1, sticky=W )
#when output from client is shown
global display
display = Text(self,width=50,height=20)
display.grid(row=1, column=1, sticky=E+W+N+S)
#where user input is taken
global prompt
prompt = Entry(self,width=50)
prompt.grid(row=3, column=1, sticky=E+W+N+S)
#Button that will send input to client
send = Button(self,text="Send",command=self.send)
send.grid(row=3, column=2, sticky=N)
get = Button(self,text="Get",command=self.get)
get.grid(row=2, column=2, sticky=S)
def get(self):
print foo
def send(self):
sent = prompt.get()
def MyThread():
global sent
sent = 2
cmd = ['nc', '-l', '-p', '50000']
process = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
out = process.stdout.read(1)
if out == '' and process.poll() != None:
break
if out != '':
display.insert(INSERT, out)
sys.stdout.write(out)
sys.stdout.flush()
def main():
root = Tk()
root.geometry("500x410+300+300")
app = Example(root)
thread = Thread(target = MyThread, args=())
thread.start()
root.mainloop()
if __name__ == '__main__':
main()
Popen.communicate()
für, die, haben Sie tatsächlich versucht? Was passiert, wenn Sie tun?communicate
wait
s für das Kind bis zum Ende und liest alle seine Ausgaben. Da die "Laufenden Prozess wird nie abgeschlossen", bedeutet dies communicate
nie wieder zurückkehren wird. So kann er es nicht verwenden.sollten Sie nicht wohl nennen GUI von einem hintergrund-thread direkt (es möglicherweise oder möglicherweise nicht arbeiten, zeitweise). Könnte man eine Warteschlange und
root.after()
an Planer ein Aufruf von GUI-thread. Vermeiden Sie die Verwendung global
unnötig, Sie könnte mit Instanz-Variablen, anstatt z.B. self.prompt
. Könnten Sie socket
, select
Module anstatt netcat
.Guter Punkt wäre es einfach mit einer Steckdose, sondern direkt von scripting
netcat
. (Brauchen Sie vielleicht noch einen separaten thread, service, socket... aber besser als 3-4 threads zum Dienst einen Teilprozess... Und eine ganze Menge einfacher. Und es werden arbeiten auf Systeme mit BSD oder Hobbit netcat statt GNU netcat oder ohne netcat überhaupt. Und so weiter.)InformationsquelleAutor Mr S | 2013-04-18
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erste, Sie müssen natürlich hinzufügen
stdin=subprocess.PIPE
zu denPopen
Konstruktor, und dann können Sieprocess.stdin.write
so wie Sieprocess.stdout.read
.Aber offensichtlich nur als
read
können blockieren, wenn keine Daten da sind, wirdwrite
blockieren kann, wenn das Kind nicht Lesen.Und auch über das offensichtliche hinaus, es ist tatsächlich sehr schwer zu bekommen, die Daten direkt für die Verwendung der Rohre in beide Richtungen mit
Popen
um ein interaktives Programm, ohne zu blockieren überall. Wenn Sie wirklich wollen, es zu tun, Blick auf die Quelle für daskommunizieren
zu sehen, wie es funktioniert. (Gibt es bekannte bugs, bevor die 3.2, also, wenn Sie sind auf 2.x, können Sie möglicherweise zu tun haben, einige Zurückportieren.) Sie implementieren müssen, um den code selbst, und wenn Sie wollen, dass es cross-Plattform, sind Sie gehen zu müssen, zu tun, den ganzen Schlamassel, dasscommunicate
hat intern (Laich-reader-und writer-threads für die Rohre, etc.), und natürlich fügen Sie eine andere thread nicht blockiert den main thread auf, jedem Versuch zu kommunizieren, und eine Art von Mechanismus, um die Nachricht zu der Haupt-thread, wenn das Kind bereit ist und so weiter.Alternativ können Sie auch Blick auf die verschiedenen "async Teilprozess" Projekte auf PyPI. Der einfachste den ich kenne ist heute
async_subprocess
, die im Grunde nur gibt Ihnen einecommunicate
, die Sie verwenden können, ohne zu blockieren.Oder, wenn Sie verwenden können
twisted
(oder evtl. auch andere event-basierter Netzwerk-frameworks), es sind Wrapper Unterprozess, der plug in seiner event-Schleife. (Wenn man warten kann, für Python 3.4, oder verwenden Sie die work-in-progresstulip
auf 3.3, jemand etwas ähnliches gebaut umtulip
, die es vielleicht in 3.4.) Undtwisted
auch weiß, wie man plug-inTkinter
, so dass Sie nicht haben, um manuell behandeln zwei separaten event-loops und die Kommunikation zwischen Ihnen.Wenn Sie nur Interesse an modernen POSIX-Systemen (nicht Windows), können Sie machen es einfacher nur darum, die Rohre im non-blocking-Modus und schreiben Sie Ihren code wie wenn du den Umgang mit sockets.
Aber die einfachste Lösung ist wohl, etwas zu verwenden, wie
pexpect
anstatt zu versuchen, Skript manuell. (Als J. F. Sebastian weist darauf hin,pexpect
Unix ist-nur, aber Sie können einen wrapper umpexpect
für Unix undwinpexpect
für Windows).Ich nicht sagen, zu verwenden
communicate
, sagte ich, müssen Sie an die Quelle, um zu sehen, all die Dinge, die Sie benötigen, um mit der Umsetzung dieses sich selbst. Was nicht leicht sein wird.Außerdem, wer hat gesagt, dass
pexpect
können nicht verwendet werden, um Skript-ein interaktives Programm? Das ist irgendwie der springende Punkt.es gibt auch
winpexpect
- Modul auf Windows.InformationsquelleAutor abarnert
Den wählen Sie - Modul in der standard-Bibliothek gemacht wird, für diese Art von situation:
Können Sie eine Liste der file-Objekte oder Datei-Deskriptoren zu
select()
wird wieder die Dateien, die Daten bereit für den lese - /Schreibzugriff oder bis ein optionales timeout.Select-Modul arbeitet sowohl auf Windows-und Unix-artigen Systemen (Linux, Mac, etc).
select
ist *nix-nur die Lösung (nur buchsen können verwendet werden, auf Windows also,select
funktioniert nicht bei Rohren). Es sollteprocess.poll()
rufen Sie irgendwo, um zu überprüfen, ob der Prozess abgeschlossen ist.Obwohl es nur worns auf *nix, das funktioniert.
Es funktioniert auf die meisten *nix-Plattformen, aber nicht alle. Und für einige, es funktioniert nur, wenn Sie explizit gesetzt, die Rohre nicht blockierende erste, was Sie nicht tun, hier.
InformationsquelleAutor Lie Ryan
Eine einfache, tragbare Lösung in Ihrem Fall mit minimalen änderungen im code möglicherweise erstellen Sie ein writer-thread, dass das abrufen von Elementen aus einer queue und schreibt Sie in das Prozess' stdin und setzen Sie dann Werte in die Warteschlange, wenn die Taste gedrückt wird:
auf Python 2;
output=process.stdin
und daheroutput.flush()
ist nutzlos in diesem Fall.Ich bin mit Python 3.x. Einen Grund, warum ich flush()(glaube Puffer wird immer aufgefüllt, bevor etwas in den stream)...nicht sicher, ob es einen besseren Weg gibt
Sowohl die Frage und meine Antwort durch die Verwendung von Python 2. Auf Python 3, die Standardeinstellung ist anders
bufsize=-1
(block buffered-Modus) undoutput.flush()
nützlich sein könnte. Es gibt auch andere änderungen, die auf Python 3 z.B., text-und Binär-Modus.InformationsquelleAutor jfs