Python and Windows Named Pipes

后端 未结 2 1776
醉酒成梦
醉酒成梦 2020-12-01 08:33

What is the proper way of communicating with named pipes on Windows from Python? I\'ve googled it, and can\'t find any packages that wrap this communication.

There a

2条回答
  •  悲&欢浪女
    2020-12-01 08:59

    In order to connect to an existing named pipe you can utilize the CreateFile API provided through the pywin32 package. Since it took me a while to put a working base together here is an example client/server which works fine for me (python 3.6.5, pywin32 223 on 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 __name__ == '__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]}")
    

    Example output client

    > 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
    

    Example output server

    > 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
    

    Obviously you'd need some error checking around the various calls but that should work.

    Additional side note: A colleague of mine ran into trouble with the pipe being closed the moment the client tried to perform I/O on it (exception claiming that "all pipe instances are busy"). It turned out that he was using os.path.exists in the client code to test whether the named pipe already existed before running CreateFile on it. This somehow breaks the pipe. So using the approach above (CreateFile wrapped in a try-except) is the safe way of trying to connect to a pipe until it has been created by the server end.

提交回复
热议问题