Bidirectional communication over unix socket (named pipe)

Discussion in 'Python' started by J Rice, Mar 8, 2006.

  1. J Rice

    J Rice Guest

    Hi, I feel like I should apologize in advance because I must be missing
    something fairly basic and fundamental here. I don't have a book on
    Python network programming (yet) and I haven't been able to find an
    answer on the net so far.

    I am trying to create a pair of programs, one (the client) will be
    short-lived (fairly) and the second (server) will act as a cache for
    the client. Both will run on the same machine, so I think a simple file
    socket is the easiest and most reliable method.

    The problem I have is that the client can send to the server, but the
    server can't send back to the client because it gets this error:

    socket.error: (107, 'Transport endpoint is not connected')

    This is despite the client waiting on a socket.recv() statement. Is
    the client really not connected, or is the server unaware of the
    connection? And how do I fix this?

    I was able to get this working by switching to AF_INET, but that is not
    what I want.

    Unix sockets are bidirectional, correct? I have never programmed one,
    but I know that programs like clamav use a socket to receive an email
    to scan and return the result.

    Any help would be greatly appreciated!

    Jeff

    *** server.py ***
    #!/usr/bin/python
    import socket
    import os, os.path
    import time

    if os.path.exists("/tmp/mysock"): os.remove("/tmp/mysock")

    server = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
    server.bind("/tmp/mysock")

    while True:
    datagram = server.recv(1024)
    if not datagram:
    break
    print datagram
    # the preceeding works, and I see the TEST TEST TEST statement the
    client sent

    time.sleep(2)
    # it dies on the next statement.
    server.send("Thank you\n")


    server.close()
    if os.path.exists("/tmp/mysock"): os.remove("/tmp/mysock")


    *** client.py: ***
    #!/usr/bin/python

    import socket

    client = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
    client.connect("/tmp/mysock")


    TX = "TEST TEST TEST"
    TX_sent = client.send(TX)

    if TX_sent <> len(TX): print "TX incomplete"

    while True:
    print "Waiting..."
    datagram = client.recv(1024)
    # the client sits here forever, I see the "waiting appear" but
    it doesn't advance beyond
    # the recv statement.
    if not datagram:
    break
    print "Received: ",datagram

    client.close()
    J Rice, Mar 8, 2006
    #1
    1. Advertising

  2. J Rice

    J Rice Guest

    OK, never fails that I find a solution once I post a problem. If I use
    a stream rather than a datagram, it seems to work fine.

    So... for my education, how would I make this work with a datagram, if
    I insisted on doing it that way?
    J Rice, Mar 8, 2006
    #2
    1. Advertising

  3. J Rice

    Donn Cave Guest

    In article <>,
    "J Rice" <> wrote:

    > The problem I have is that the client can send to the server, but the
    > server can't send back to the client because it gets this error:
    >
    > socket.error: (107, 'Transport endpoint is not connected')
    >
    > This is despite the client waiting on a socket.recv() statement. Is
    > the client really not connected, or is the server unaware of the
    > connection? And how do I fix this?


    You can either connect() as well as bind(), or use
    sendto(data, file)

    Donn Cave,
    Donn Cave, Mar 8, 2006
    #3
  4. J Rice

    J Rice Guest

    Hi Donn,
    Not sure I fully understand your suggestion. bind() only works once --
    I can't bind again in the client. Same thing with connect() -- once I
    issue a connect in the server, it rejects it in the client.

    Doing this as a stream works for what I want, but I would like to
    understand why it didn't work with datagram.
    J Rice, Mar 8, 2006
    #4
  5. J Rice

    Donn Cave Guest

    In article <>,
    "J Rice" <> wrote:

    > Hi Donn,
    > Not sure I fully understand your suggestion. bind() only works once --
    > I can't bind again in the client. Same thing with connect() -- once I
    > issue a connect in the server, it rejects it in the client.
    >
    > Doing this as a stream works for what I want, but I would like to
    > understand why it didn't work with datagram.


    Right, bind should be on one end only, as it creates
    the actual socket file.

    Connect works on either end, with SOCK_DGRAM. From
    man 2 connect:

    The parameter s is a socket. If it is of type SOCK_DGRAM,
    this call specifies the peer with which the socket is to be
    associated; this address is that to which datagrams are to
    be sent, and the only address from which datagrams are to be
    received. If the socket is of type SOCK_STREAM, this call
    attempts to make a connection to another socket.

    However, even if we're straight on this, I confess I
    have only addressed your question about the unconnected
    endpoint.

    The other part of the problem remains, as I don't know
    how to get data to actually go both ways. I was a little
    surprised by this, and have not been able to scare up any
    explicit documentation, but the only example program I
    could find for two-way UNIX domain datagram IPC, uses two
    sockets, not one -
    http://docs.hp.com/en/B2355-90136/ch07s06.html

    Donn Cave,
    Donn Cave, Mar 8, 2006
    #5
  6. J Rice

    Ross Ridge Guest

    Donn Cave wrote:
    > The other part of the problem remains, as I don't know
    > how to get data to actually go both ways.


    The problem here is that datagram sockets don't send data from one
    process to another, they send data from one address to another. In
    this case, the client isn't able to receive data through it's socket
    because the socket isn't bound any address. Calling connect() on the
    datagram socket doesn't give the socket an address to receive data
    with, just a default address to send data to. Since the server's
    socket is the only socket bound to "/tmp/mysock" it's the only the only
    process that can receive datagrams sent to that address. That includes
    any datagrams the server itself sends to the address.

    You need multiple Unix domain address so each process has an address it
    can receive data with, and an address other than it's own that it can
    send data to.

    Ross Ridge
    Ross Ridge, Mar 9, 2006
    #6
  7. J Rice

    J Rice Guest

    Thank you, that answers my question! And it works fine with stream, so
    I can do what I want as well.
    J Rice, Mar 11, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. lee, wonsun
    Replies:
    1
    Views:
    480
    Jack Klein
    Nov 2, 2004
  2. Manfred Balik
    Replies:
    12
    Views:
    6,572
    Marc Guardiani
    Sep 10, 2006
  3. Gernot Frisch
    Replies:
    7
    Views:
    1,487
    Jorgen Grahn
    Dec 18, 2010
  4. papahuhn

    bidirectional pipe & inetd

    papahuhn, May 30, 2007, in forum: Perl Misc
    Replies:
    1
    Views:
    126
  5. all mail refused

    perlipc bidirectional unix domain socket

    all mail refused, Sep 22, 2007, in forum: Perl Misc
    Replies:
    6
    Views:
    447
    all mail refused
    Sep 23, 2007
Loading...

Share This Page