it-swarm.com.de

Python und Windows Named Pipes

Wie kann ich mit Named Pipes unter Windows von Python aus kommunizieren? Ich habe es gegoogelt und kann keine Pakete finden, die diese Kommunikation einschließen.

Es gibt: 

Ich muss nur eine Verbindung zu einer vorhandenen Named Pipe herstellen und lesen/schreiben. Ich hatte vorher nur die Kommunikation mit der seriellen Schnittstelle (mit pySerial) versucht, und ich bin überrascht, wie wenig Informationen ich über Named Pipes im Vergleich dazu finden konnte. Es gibt in der Regel jede Menge Anleitungen für Python.

Ich freue mich über jede Hilfe.

7
Ray P.

Um eine Verbindung zu einer vorhandenen Named Pipe herzustellen, können Sie die CreateFile-API verwenden, die über das pywin32-Paket bereitgestellt wird. Da ich eine Weile gebraucht habe, um eine funktionierende Basis zusammenzustellen, ist hier ein Beispiel für einen Client/Server, der für mich gut funktioniert (python 3.6.5, pywin32 223 unter Windows 10 Pro x64):

import time
import sys
import win32pipe, win32file, pywintypes


def pipe_server():
    print("pipe server")
    count = 0
    pipe = win32pipe.CreateNamedPipe(
        r'\\.\pipe\Foo',
        win32pipe.PIPE_ACCESS_DUPLEX,
        win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
        1, 65536, 65536,
        0,
        None)
    try:
        print("waiting for client")
        win32pipe.ConnectNamedPipe(pipe, None)
        print("got client")

        while count < 10:
            print(f"writing message {count}")
            # convert to bytes
            some_data = str.encode(f"{count}")
            win32file.WriteFile(pipe, some_data)
            time.sleep(1)
            count += 1

        print("finished now")
    finally:
        win32file.CloseHandle(pipe)


def pipe_client():
    print("pipe client")
    quit = False

    while not quit:
        try:
            handle = win32file.CreateFile(
                r'\\.\pipe\Foo',
                win32file.GENERIC_READ | win32file.GENERIC_WRITE,
                0,
                None,
                win32file.OPEN_EXISTING,
                0,
                None
            )
            res = win32pipe.SetNamedPipeHandleState(handle, win32pipe.PIPE_READMODE_MESSAGE, None, None)
            if res == 0:
                print(f"SetNamedPipeHandleState return code: {res}")
            while True:
                resp = win32file.ReadFile(handle, 64*1024)
                print(f"message: {resp}")
        except pywintypes.error as e:
            if e.args[0] == 2:
                print("no pipe, trying again in a sec")
                time.sleep(1)
            Elif e.args[0] == 109:
                print("broken pipe, bye bye")
                quit = True


if __== '__main__':
    if len(sys.argv) < 2:
        print("need s or c as argument")
    Elif sys.argv[1] == "s":
        pipe_server()
    Elif sys.argv[1] == "c":
        pipe_client()
    else:
        print(f"no can do: {sys.argv[1]}")

Beispiel für einen Ausgabeclient

> python pipe_test.py c
pipe client
no pipe, trying again in a sec
no pipe, trying again in a sec
no pipe, trying again in a sec
message: (0, b'0')
message: (0, b'1')
message: (0, b'2')
message: (0, b'3')
message: (0, b'4')
message: (0, b'5')
message: (0, b'6')
message: (0, b'7')
message: (0, b'8')
message: (0, b'9')
broken pipe, bye bye

Beispiel Ausgabeserver

> python pipe_test.py s
pipe server
waiting for client
got client
writing message 0
writing message 1
writing message 2
writing message 3
writing message 4
writing message 5
writing message 6
writing message 7
writing message 8
writing message 9
finished now

Natürlich müssten Sie bei den verschiedenen Anrufen einige Fehler überprüfen, aber das sollte funktionieren.

Zusätzliche Randbemerkung: Ein Kollege von mir hatte Probleme mit dem Schließen der Pipe, als der Client versuchte, E/A-Vorgänge durchzuführen (Ausnahme, dass "alle Pipe-Instanzen beschäftigt sind"). Ich stellte fest, dass er os.path.exists im Clientcode verwendete, um zu testen, ob die Named Pipe bereits vorhanden war, bevor CreateFile darauf ausgeführt wurde. Das bricht irgendwie die Pfeife. Wenn Sie den obigen Ansatz verwenden (CreateFile in Try-Exceptions eingeschlossen), ist dies die sichere Methode, eine Verbindung zu einer Pipe herzustellen, bis diese vom Server erstellt wurde.

6
ChrisWue

Ich habe Erfolg mit etwas wie dem folgenden Fragment. Dieser Code wird von CaptureSetup/Pipes - Python unter Windows - Das Wireshark Wiki abgeleitet. Es erfordert win32pipe und win32file aus dem pywin32 -Paket.

# pipename should be of the form \\.\pipe\mypipename
pipe = win32pipe.CreateNamedPipe(
        pipename,
        win32pipe.PIPE_ACCESS_OUTBOUND,
        win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT,
        1, 65536, 65536,
        300,
        None)
try:
    win32pipe.ConnectNamedPipe(pipe, None)

    while True:
        some_data = b'12345...'
        win32file.WriteFile(pipe, some_data)
        ...
finally:
    win32file.CloseHandle(pipe)

Ich weiß nicht, ob das Rohr zu 100% korrekt ist.

Sie bezogen sich auf Die Gefahren und Triumphe eines Geeks: Named Pipes zwischen C # und Python - Jonathon Reinhart. Ich habe es ausprobiert, konnte aber die Named Pipe nicht erstellen. Ich frage mich, ob der Code nur dazu dient, eine Named Pipe zu öffnen, die bereits von einem anderen Prozess erstellt wurde.

0
Craig McQueen