Python and Windows Named Pipes Python and Windows Named Pipes windows windows

Python and Windows Named Pipes


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 timeimport sysimport win32pipe, win32file, pywintypesdef 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 = Trueif __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 cpipe clientno pipe, trying again in a secno pipe, trying again in a secno pipe, trying again in a secmessage: (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 spipe serverwaiting for clientgot clientwriting message 0writing message 1writing message 2writing message 3writing message 4writing message 5writing message 6writing message 7writing message 8writing message 9finished 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.


I have success with something like the following fragment. This code is derived from CaptureSetup/Pipes — Python on Windows — The Wireshark Wiki. It requires win32pipe and win32file from the pywin32 package.

# pipename should be of the form \\.\pipe\mypipenamepipe = 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)

I don't know if it's 100% correct in the way it closes the pipe.

You referred to The Perils and Triumphs of Being a Geek: Named Pipes between C# and Python—Jonathon Reinhart. I tried it, but it wasn't able to create the named pipe. I wonder if that code only works to open a named pipe that has already been created by another process.