[zeromq-dev] Getting started with ruby bindings

Martin Sustrik sustrik at 250bpm.com
Wed Apr 14 17:36:49 CEST 2010


Hi Brian,

> * Compiling the C/C++ code was completely hassle-free - excellent!
>   (zeromq-2.0.6 tarball, under Ubuntu Hardy i386)
> 
> * I installed the gem version of the ruby bindings, which gave me
>   rb-zmq-0.0.6.

The gem version is out of date. The guy who created it doesn't maintain 
it so I'm removing the link from the webpage.

>   According to the instructions at http://www.zeromq.org/bindings:ruby you
>   have to have built libzmq using '--with-c' option, but this option doesn't
>   seem to exist (according to ./configure --help), and it worked without it.

Ok. Fixed.

> * The same page says that the ruby binding source code is at
>   http://github.com/sustrik/rbzmq
>   but this appears to be something very old; at least, there's lots of
>   stuff in the gem which is not in the git repo. I'd like to get hold of
>   the real source for the gem.

Other way round. Gem is old, git is new.

> * However the git repo does have a perf/ directory with some tests, which
>   the gem doesn't. I had to make some fixes to the applications to make
>   them run:
> 
> --- /home/candlerb/git/rbzmq/perf/local_lat.rb	2010-04-14 13:56:40.000000000 +0100
> +++ local_lat.rb	2010-04-14 14:07:11.000000000 +0100
> @@ -16,7 +16,7 @@
>  #    You should have received a copy of the Lesser GNU General Public License
>  #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
>  
> -require 'zmq'
> +require 'rb_zmq'
>  
>  if ARGV.length != 3
>  	puts "usage: local_lat <bind-to> <message-size> <roundtrip-count>"
> @@ -27,9 +27,9 @@
>  message_size = ARGV[1].to_i
>  roundtrip_count = ARGV[2].to_i
>  			
> -ctx = ZMQ::Context.new(1, 1, 0)
> -s = ctx.socket(ZMQ::REP);
> -s.bind(bind_to);
> +ctx = Context.new(1, 1, 0)
> +s = Socket.new(ctx, REP)
> +s.bind(bind_to)
>  
>  for i in 0...roundtrip_count do
>      msg = s.recv(0)
> --- /home/candlerb/git/rbzmq/perf/remote_lat.rb	2010-04-14 13:56:40.000000000 +0100
> +++ remote_lat.rb	2010-04-14 14:07:39.000000000 +0100
> @@ -16,7 +16,7 @@
>  #    You should have received a copy of the Lesser GNU General Public License
>  #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
>  
> -require 'zmq'
> +require 'rb_zmq'
>  
>  if ARGV.length != 3
>  	puts "usage: remote_lat <connect-to> <message-size> <roundtrip-count>"
> @@ -27,9 +27,9 @@
>  message_size = ARGV[1].to_i
>  roundtrip_count = ARGV[2].to_i
>  					
> -ctx = ZMQ::Context.new(1, 1, 0)
> -s = ctx.socket(ZMQ::REQ);
> -s.connect(connect_to);
> +ctx = Context.new(1, 1, 0)
> +s = Socket.new(ctx, REQ)
> +s.connect(connect_to)
>  
>  msg = "#{'0'*message_size}"
>  
> 
> * I think it was a really bad idea to drop the ZMQ namespace. In particular,
> Ruby has its own Socket class for low-level IP operations, and it causes
> havoc if you try to use both:
> 
> $ irb --simple-prompt
>>> require 'socket'
> => true
>>> Socket
> => Socket
>>> Socket.object_id
> => -610038958
>>> require 'rubygems'
> => true
>>> require 'rb_zmq'
> NameError: Socket is already defined
> 	from /usr/lib/ruby/gems/1.8/gems/rb-zmq-0.0.6/lib/rbzmq.so
> 	from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
> 	from /usr/lib/ruby/gems/1.8/gems/rb-zmq-0.0.6/lib/rb_zmq.rb:1
> 	from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
> 	from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
> 	from (irb):5
> 	from /usr/local/lib/site_ruby/1.8/rubygems/exceptions.rb:19
> 
> So any ruby app which tries to use ZMQ with, say, HTTP, is likely to fail.
> 
> With the ZMQ namespace you can always do "include ZMQ" to avoid having to
> prefix everything with ZMQ:: (and you can get to the top-level Socket using
> ::Socket)
> 
> I might contribute a fix to this, but being unable to find the source for
> the current rb_zmq, I can't (see above)

:)

Other way round. Namespace was added rather than removed.

> * As a general point: I would like to some more documentation to get a
> better understanding of the semantics of ZMQ operations.
> 
> Simple example: if I connect one P2P socket to another P2P socket, what
> do I gain above a regular TCP socket connection, apart from message framing?

Async message queueing. Auto-reconnect. Higher message throughput.

> More complex example: if a REQ/REP socket can only handle lock-step
> request-response, how do I handle concurrent requests?  In the C API, I
> guess I could I create multiple threads and call zmq_recv in them
> concurrently, is that right?

Right.

>  What about in Ruby, given that Ruby (1.8) has
> only green threads, i.e. a single POSIX thread?

No idea how ruby scheduling works, sorry.

> * I looked at the source for zmq_queue / zmq_streamer / zmq_forwarder but
> can't really see the difference between them. Are they for the different
> messaging patterns?

Yes. zmq_queue is for REQ/REP, zmq_streamer is for DOWNSTREAM/UPSTREAM 
and zmq_forwarder is for PUB/SUB.

> * I'd also like to see some documentation of the on-the-wire protocol. I
> haven't read through all the white papers yet, but I don't see it at first
> glance.  This is partly for idle curiosity, but also for the possibility of
> implementing a pure-ruby version.  I would have to understand the semantics
> better too of course.

Wire protocol is trivial. See zmq_tcp(7) man page.

> However I have to say this all looks very promising, and I think the "small
> building blocks" approach is a very good one to take.

Thanks!
Martin



More information about the zeromq-dev mailing list