[zeromq-dev] Can't bind same ZMQ_UP/DOWNSTREAM multiple times.
Oliver Smith
oliver at kfs.org
Tue Aug 17 06:39:05 CEST 2010
On 8/16/2010 12:07 PM, Pieter Hintjens wrote:
> Hi Oliver,
>
> I can repeat my previous reply. After reading your email I still
> don't understand why you need to bind to the same endpoint twice, and
> why you expect this to work (it won't).
>
> You cannot bind two sockets to a single endpoint. It's not a legal semantic.
>
> So what in fact is your question? Sorry if I missed it.
I did do a good job of making that a bit hidden.
The question: What is the right pattern for doing this -- 1 -> N -> M ->
1 four stage parallelism.
Why it's even a question: Remember, "ZeroMQ sockets aren't /sockets/".
That just happens to be one of the underlying mechanisms.
From a networking perspective, I understand why multiple binds don't
work. And setting SO_REUSEADDR would just be messy...
But I would have thought that internally if multiple socket_ts tried to
bind to the same IP socket address ///via the same context/// you would
have handled that internally the same way that you handle multiple
connects: thus allowing multiple threads within an application to
service the same socket.
Consider:
8x--- snip ---x8
import zmq
import re
ctx = zmq.Context(8)
class HTTPWorker(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.sock = ctx.socket(zmq.REP)
self.sock.bind("tcp://0.0.0.0:80")
def run(self):
urlMatch = re.compile(r'^GET\s+([/a-zA-Z0-9_.%-]+)')
while True:
msg = self.sock.recv()
matches = urlMatch.match(msg)
if matches and matches.group(1):
content = readFile(matches.group(1))
reply = headers(matches.group(1), content)
self.sock.send(reply)
8x--- snip ---x8
This would allow one processes to have multiple threads servicing a
single TCP socket endpoint without the need to go through a device or
have the operator fork multiple processors.
I do absolutely understand why "self.sock.bind(same address multiple
times)" on a single machine does not work. But that requires the
end-user to be aware of the underlying network basis of the function of
"bind".
Now consider:
# X threads are going to receive transparently
# multiplexed work from Q sources.
self.workin = ctx.socket(zmq.DOWNSTREAM)
self.workin.connect("inproc://stage1-worker")
# Those X stage1 workers are going to forward
# additional work to Y transparently
# multiplexed stage 2 workers.
self.workout = ctx.socket(zmq.UPSTREAM)
self.workout.bind("inproc://stage2-workers")
Again -- I understand why, under the hood, BSD's bind(3) function
returns address already in use.
But I'm not using bind(3), I'm using zmq->context->bind. Therefore the
answer to the question should be in ZeroMQ context terms and not
sockets-api terms... If the answer was "because they are using different
contexts, and only one context can bind to a socket address" - that
would work. But "only one endpoint can bind to a socket address even on
the same context as the other endpoint" doesn't... Certainly not in many
sample use cases.
- Oliver
More information about the zeromq-dev
mailing list