Seite 1 von 1
subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 13:55
von init-0
Hallo,
Ich würde gerne den output von einem subprocess an einen socket weiterleiten und input vom gleichen socket an den prozess.
Meine erste idee war ein neues socketobjekt zu erstellen
Code: Alles auswählen
class newSocket(socket.socket):
def write(*args, **kwargs):
return self.send(*args, **kwargs)
def read(*args, **kwargs):
return self.recv(*args, **kwargs)
und das beim subprocess aufruf als stdin und stdout anzugeben. Dafür bekomme ich aber immer einen badfiledescriptor, für newSocket.fileno.
Die alternative die mir dazu einfällt ist PIPES als parameter anzugeben und dann permanent den input in einer schleife weiterzuleiten.
Das Problem dabei ist, dass ich, wenn ich versuche zu lesen sowohl beim socket als auch beim subprocess stecken bleiben könnte, wenn kein neuer input kommt.
Wenn ich aber jetzt grade auf den output vom prozess warte und selbst etwas neues senden will, stecke ich fest.
Gibt es irgend eine Möglichkeit für socket.recv und process.stdout.read einfach einen leeren string zu bekommen, anstatt endlos zu warten, bis man etwas bekommt?
Re: subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 14:56
von BlackJack
@init-0: Unter welchen Systemen muss das denn laufen? Unter Unixoiden habe Socket-Objekte eine `makefile()`-Methode die ein Dateiobjekt zurück gibt.
Ansonsten müsstest Du bei der PIPEs-Lösung mit Threads arbeiten. Das `select`-Modul wäre auch eine Möglichkeit, aber wieder nicht unter Windows, weil da `select` nur mit Sockets funktioniert. Vielleicht auch der Grund warum `socket.makefile()` dort nicht geht.
Re: subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 15:01
von init-0
Ich bin leider unter windows

Re: subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 15:54
von init-0
Ich hatte mir jetzt sowas überlegt, aber das funktioniert nicht ganz
Code: Alles auswählen
import subprocess
import threading
class Reader(threading.Thread):
def __init__(self, pipe):
threading.Thread.__init__(self)
self.pipe = pipe
def readHandler(self, data):
print(data.decode(), end="")
def run(self):
while 1:
data = self.pipe.readline()
self.readHandler(data)
class Process:
def __init__(self, command):
self.process = subprocess.Popen(command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
self.stdoutreader = Reader(self.process.stdout)
self.stdoutreader.start()
#self.stdoutreader = Reader(self.process.stderr)
#self.stdoutreader.start()
if __name__ == "__main__" and 1:
process = Process("cmd.exe")
while 1:
i = input().encode()
process.process.stdin.write(i+b"\t\n")
process.process.stdin.flush()
das scheint zu selten zu aktualisieren
Code: Alles auswählen
[Code=python file=Untitled.py]>>>
echo test
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
C:\Users\init\Desktop>echo test
test
C:\Users\init\Desktop>
Re: subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 16:24
von BlackJack
@init-0: So etwas funktioniert nur wenn nicht nur Dein Programm „flush”t also nicht puffert, sondern das Programm auf der anderen Seite auch nicht. Und das ist etwas was Du nicht beeinflussen kannst wenn der Programmierer des Programms auf der anderen Seite das nicht vorsieht! Übrigens ist das Programm auf der anderen Seite bei Dir eine Shell (wahrscheinlich ``cmd.exe``). Das heisst Du sendest das an die Shell und die sendet das dann an das ``cmd.exe`` weiter welches Du explizit gestartet hast. Und auf dem Rückweg gehen die Daten auch diesen Umweg. Das erscheint mir sinnlos.
Re: subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 16:54
von init-0
Ich verstehe nicht so ganz was du meinst. ich will den input für den subprocess über das netzwerk empfangen und den output auch genau dahin senden.
Re: subprocess IO weiterleiten
Verfasst: Montag 24. März 2014, 17:26
von BlackJack
@init-0: Ich verstehe nicht was Du nicht verstehst‽ Das kannst Du grundsätzlich so machen, du hast nur keinen Einfluss darauf was wo gepuffert wird solange die beteiligten externen Programme, ob nun auf der anderen Seite einer Pipe oder auf der anderen Seite eines Sockets, nicht entweder von Dir sind, oder Möglichkeiten bieten das Pufferverhalten zu kontrollieren.
Re: subprocess IO weiterleiten
Verfasst: Dienstag 25. März 2014, 00:17
von init-0
Achso.
Das Programm scheint aber immernoch ein paar einschränkungen zu haben.
Selbst wenn ich die Pipe nur mit
abfrage, bekomme ich immernur neue daten, wenn cmd.exe ein newline sendet. Ich denke mal das hat was mit dem angesprochenen flush zu tun. Kann man das denn irgendwie umgehen?
Ausserdem bekomme ich garkeinen output, wenn ich einen neuen prozess ausführe. wenn ich aus dem code heraus die python shell aufrufen will, bekomme ich überhaupt keinen output

Re: subprocess IO weiterleiten
Verfasst: Dienstag 25. März 2014, 00:59
von BlackJack
@init-0: Dann scheint `cmd.exe` auf seiner Seite der Pipe zeilenbasiert zu puffern. Wie gesagt, wenn der Programmierer da nichts für vorgesehen hat, zum Beispiel eine Option, dann kannst Du da nichts machen.
Zu dem Python-Prozess: Python merkt dass es nicht mit einem Terminal verbunden ist, und darum ist das auch keine interaktive Shell, sondern ein Python-Prozess der das auszuführende Programm auf seiner Standardeingabe liest. In dem Fall möchtest Du vielleicht die Option ``-i`` bei dem Prozess verwenden um auch ohne Terminal eine interaktive Shell zu bekommen, und die ``-u``-Option damit der Python Prozess nicht puffert.
Code: Alles auswählen
$ python --help
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
[…]
-i : inspect interactively after running script; forces a prompt even
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
[…]
-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
see man page for details on internal buffering relating to '-u'
[…]
- : program read from stdin (default; interactive mode if a tty)
[…]
Edit: Und wenn Du `stderr` PIPEst, dann solltest Du das auch auslesen, sonst blockiert Dir das alles wenn die Gegenseite da etwas rein schreibt und der Puffer voll ist.
Re: subprocess IO weiterleiten
Verfasst: Sonntag 30. März 2014, 21:50
von init-0
Ich hab
hier für windows etwas passendes gefunden, und versucht das in ctypes nach zu machen
Code: Alles auswählen
from ctypes import *
from ctypes.wintypes import *
LPTSTR = POINTER(c_char)
STD_INPUT_HANDLE = DWORD(-10)
STD_OUTPUT_HANDLE = DWORD(-11)
STD_ERROR_HANDLE = DWORD(-12)
class STARTUPINFO(Structure):
_fields_ = [
("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute", DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserverd2",LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),
]
class PROCESS_INFORMATION(Structure):
_fields_ = [
("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),
]
if __name__ == '__main__':
cmd = b"cmd.exe"
buff_size = DWORD(64)
buff = create_string_buffer(64)
chars = DWORD(0)
si = STARTUPINFO()
pi = PROCESS_INFORMATION()
si.cb = sizeof(si)
#Zero Memory si, pi
proc = windll.kernel32.CreateProcessA(
c_char_p(0),
c_char_p(cmd),
None,
None,
False,
0,
None,
None,
byref(si),
byref(pi),
)
stdin = windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
stdout = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
#stderr.
proc_stdin = si.hStdInput
proc_stdout = si.hStdOutput
while not windll.kernel32.ReadConsoleA(stdin, buff, sizeof(buff),
byref(chars), None):
writtenThisTime = DWORD(0)
written = DWORD(0)
while written.value < chars.value:
windll.kernel32.WriteConsoleA(
proc_stdout,
buff+written,
chars-written,
byref(writtenThisTime),
None,
)
written += writtenThisTime
Leider klappt die while Schleife noch nicht so ganz. written bleibt bei mir irgendwie immer 0 und das in der zweiten while Schleife mit buff+written ist ja auch unsinnig.
Kann man mit CreateProcess auch bestimmen, dass das nicht im gleichen Konsolenfenster geöffnet werden soll?
Re: subprocess IO weiterleiten
Verfasst: Sonntag 30. März 2014, 22:05
von Sirius3
@init-0: was von dem, was Du hier umständlich mit Win-API aufrufen zu tun versuchst, läßt sich nicht mit subprocess erledigen?