Skip to content

Instantly share code, notes, and snippets.

@pauldix
Created July 13, 2011 21:34
Show Gist options
  • Save pauldix/1081387 to your computer and use it in GitHub Desktop.
Save pauldix/1081387 to your computer and use it in GitHub Desktop.
Y U NO WORK?!!!!
# here's the dealer socket in one process
require 'ffi-rzmq'
@context = ZMQ::Context.new(1)
@sock = @context.socket(ZMQ::XREQ)
@sock.bind("tcp://*:5550")
count = 0
while true do
count += 1
puts count
@sock.send_string("#{count} messge", 0)
sleep 1
end
# and here's the REP socket in another process
require 'ffi-rzmq'
@context = ZMQ::Context.new(1)
@socket = @context.socket(ZMQ::REP)
@socket.connect("tcp://localhost:5550")
while true do
puts "attempting recv_string"
puts @socket.recv_string
end
# and the output on the Dealer side:
# 1
# 2
# 3
# ...
# and on the REP side:
# attempting recv_string
# then nothing else. the dealer keeps going, but the REP is just stuck. If I don't start the REP then the
# dealer just waits after the first message.
@chuckremes
Copy link

Change the XREQ/DEALER code to write a null message part to separate the routing envelope from the message body.

while true do
count += 1
puts count
@sock.send(ZMQ::Message.new, ZMQ::SNDMORE)
@sock.send_string("#{count} message", 0)
sleep 1
end

Try that. I haven't tested it but it ought to work.

@chuckremes
Copy link

This code can't ever work.

A REP socket enforces a very strict recv/send/recv/send pattern. Your code for the REP socket only ever does a recv. The second time you attempt to recv (without an intervening send) and it will fail. The DEALER socket doesn't have this issue; there is no state machine enforcing that pattern.

Here is some working code. Note that I also switched around which socket does a bind and which does a connect. It's good practice to have the receiver up and running first.

require 'rubygems'
require 'ffi-rzmq'

@context = ZMQ::Context.new(1)
@socket = @context.socket(ZMQ::REP)
@socket.bind("tcp://127.0.0.1:5550")

while true do
  puts "attempting recv_string"
  puts @socket.recv_string
  @socket.send_string("foo")
end
require 'rubygems'
# here's the dealer socket in one process
require 'ffi-rzmq'

@context = ZMQ::Context.new(1)
@sock = @context.socket(ZMQ::XREQ)
@sock.connect("tcp://127.0.0.1:5550")

count = 0
while true do
  count += 1
  puts count
  @sock.send(ZMQ::Message.new, ZMQ::SNDMORE)
  @sock.send_string("#{count} messge", 0)
  @sock.recv_string
  sleep 1
end

I should have seen the solution sooner. Time for bed!

@pauldix
Copy link
Author

pauldix commented Jul 14, 2011

oh thank god. I knew about the requirement for having the REP do a send. I just didn't bother to put that in because it never got past the first receive. The example in the guide needs to be updated since it doesn't have that first send on the XREQ socket.

Finally, why would I have the REP be the one to bind? My use case is that the XREQ is part of a queue broker. Only one of them and many REP workers to process stuff.

@chuckremes
Copy link

Like I said, it's good practice to have the receiver(s) up and running first.

For a setup similar to the one you describe, I always put a QUEUE device in between the producer and consumer. I find it easier to manage having each producer (and each consumer) connect to a single address (the device). The way you describe your setup, each producer would have to know the address of every consumer; I find that to be more fragile in my environment, so I use devices to simplify the topology.

Either way will work. 0mq gives you lots of flexibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment