Bidirectional communication over unix socket (named pipe)

J

J Rice

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

J Rice

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?
 
D

Donn Cave

"J Rice said:
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, (e-mail address removed)
 
J

J Rice

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.
 
D

Donn Cave

"J Rice said:
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, (e-mail address removed)
 
R

Ross Ridge

Donn said:
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
 
J

J Rice

Thank you, that answers my question! And it works fine with stream, so
I can do what I want as well.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,158
Latest member
Vinay_Kumar Nevatia
Top