[zeromq-dev] Getting started with ruby bindings

Brian Candler B.Candler at pobox.com
Wed Apr 14 16:20:01 CEST 2010


Hello, I'm just starting with zeromq and would like to give some feedback on
the experience from a newcomer's point of view.

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

  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.

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

* 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)

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

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?  What about in Ruby, given that Ruby (1.8) has
only green threads, i.e. a single POSIX thread?

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

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

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.

Regards,

Brian.



More information about the zeromq-dev mailing list