Duplex Named Pipe with Python Server and C# Clients

Hi,

I am trying to set up a Python server to process objects from C# (.NET) clients
with a duplex named pipe. I’ve seen some good examples for setting up pipes,
but it’s going the other way: With the server in C# and Python as the client.
Instead of “NamedPipeServerStream”, I need to use “NamedPipeClientStream”
in .NET.

I came across the following code on SO:

The code as downloaded has problems.

sock.bind(SOCK_PATH)

:> TypeError: bind(): AF_INET address must be tuple, not str

My immediate problem is to figure out what sock.bind wants in the way of a tuple.
I thought that giving it a port number might be what it wants, but that is wrong:
sock.bind((SOCK_PATH, 443))
#socket.gaierror: [Errno 11001] getaddrinfo failed

Can anyone please help me figure this out?

If anyone knows of a good working example on how to open a named pipe
in Python, then have clients in C# send objects through the pipe then
receive the modified object I would very much appreciate it if you’d
clue me in.

THANKS!

Here is the code:

Python

#!/usr/bin/python3

import socket
import os
import struct

#SOCK_PATH = "/tmp/CoreFxPipe_mySocket"
#  TRY changing this to the same within C#
# 
SOCK_PATH = "/mySocket"
#  SOCK_PATH = r'\\.\pipe\mySocket'

# with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
# Change socket.AF_UNIX to socket.AF_INET for Windows
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    try:
        os.remove(SOCK_PATH)
    except OSError:
        pass
    #sock.bind(SOCK_PATH)
    #Traceback (most recent call last):
    #sock.bind(SOCK_PATH)
    #TypeError: bind(): AF_INET address must be tuple, not str

    sock.bind((SOCK_PATH, 443))
    #socket.gaierror: [Errno 11001] getaddrinfo failed

    sock.listen()
    conn, addr = sock.accept()
    with conn:
        try:
            while True:
                amount_expected = struct.unpack('I', conn.recv(4))[0]
                print("amount_expected :", amount_expected)

                message = conn.recv(amount_expected)
                print("Received message : ", message.decode())

                # Send data
                message_rev = message[::-1].decode()
                print("Sent message (reversed) : ", message_rev)

                conn.sendall(
                    struct.pack(
                        'I',
                        len(message_rev)
                    )
                    + message_rev.encode('utf-8')
                )

        except (struct.error, KeyboardInterrupt) as e:
            print(e)

        finally:
            print('closing socket')

C# (.NET)

class PipeClient
{
public void PipeClient_Main()
{
using (NamedPipeClientStream
pipeClient = new NamedPipeClientStream
(“.”, “mySocket”, PipeDirection.InOut))
{

        // Connect to the pipe or wait until the pipe is available.
        Console.WriteLine("Attempting to connect to pipe...");
        pipeClient.Connect();

        try
        {
            // Read user input and send that to the client process.
            using (BinaryWriter _bw = new BinaryWriter(pipeClient))
            using (BinaryReader _br = new BinaryReader(pipeClient))
            {
                while (true)
                {
                    //sw.AutoFlush = true;
                    Console.Write("Enter text: ");
                    var str = Console.ReadLine();

                    var buf = Encoding.ASCII.GetBytes(str);     // Get ASCII byte array
                    _bw.Write((uint)buf.Length);                // Write string length
                    _bw.Write(buf);                              // Write string
                    Console.WriteLine("Wrote: \"{0}\"", str);
                    Console.WriteLine("Let's hear from the server now..");

                    var len = _br.ReadUInt32();
                    var temp = new string(_br.ReadChars((int)len));

                    Console.WriteLine("Received from client: {0}", temp);
                }
            }
        }
        // Catch the IOException that is raised if the pipe is broken
        // or disconnected.
        catch (IOException e)
        {
            Console.WriteLine("ERROR: {0}", e.Message);
        }

    }
    Console.Write("Press Enter to continue...");
}

}

1 Like

I am trying to set up a Python server to process objects from C# (.NET)
clients
with a duplex named pipe. I’ve seen some good examples for setting up pipes,
but it’s going the other way: With the server in C# and Python as the client.
Instead of “NamedPipeServerStream”, I need to use “NamedPipeClientStream”
in .NET.

So… Python runs the server side, accepting connections.

I came across the following code on SO:
Named Pipes IPC: Python server, C# Client - Stack Overflow

The code as downloaded has problems.

sock.bind(SOCK_PATH)
:> TypeError: bind(): AF_INET address must be tuple, not str

I’ll try to provide some context.

Bear in mind that my experience is UNIX, where the equivalent object is
a “UNIX domain socket”, meaning a socket with a filesystem name, like
your Windows named pipe. (In UNIX there are also “named pipes”, but they
are much simpler simplex objects.)

If you’re using a TCP socket then the server allocates an AF_INET
socket, then binds it to an (address,port) pair, being the local address
and port on which to listen.

If you’re using a named filesystem socket (in UNIX a “UNIX domain
socket” and presumably in Windows a “named pipe”) then the address is
the filesystem path.

See the “Socket Families” stuff here:

https://docs.python.org/3/library/socket.html

So in your error above you’ve presumably allocated an AF_INET socket.
You want to allocat an AF_UNIX socket.

My immediate problem is to figure out what sock.bind wants in the way
of a tuple.
I thought that giving it a port number might be what it wants, but that is wrong:
sock.bind((SOCK_PATH, 443))
#socket.gaierror: [Errno 11001] getaddrinfo failed

Yeah, that doesn’t make sense. You just want SOCK_PATH. Make an AF_UNIX
socket, not AF_INET.

BTW, have you looked at the socketserver module?

https://docs.python.org/3/library/socketserver.html

which has a UnixStreamServer that does all this for you.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like