class ZMQ::Message
The factory constructor optionally takes a string as an argument. It will copy this string to native memory in preparation for transmission. So, don't pass a string unless you intend to send it. Internally it calls copy_in_string.
Call close to release buffers when you are done with the data.
(This class is not really zero-copy. Ruby makes this near impossible since Ruby objects can be relocated in memory by the GC at any time. There is no way to peg them to native memory or have them use non-movable native memory as backing store.)
Message represents ruby equivalent of the
zmq_msg_t
C struct. Access the underlying memory buffer and
the buffer size using the data and
size methods respectively.
It is recommended that this class be composed inside another class for access to the underlying buffer. The outer wrapper class can provide nice accessors for the information in the data buffer; a clever implementation can probably lazily encode/decode the data buffer on demand. Lots of protocols send more information than is strictly necessary, so only decode (copy from the 0mq buffer to Ruby) that which is necessary.
When you are done using a received message object, call close to release the associated buffers.
received_message = Message.create if received_message rc = socket.recvmsg(received_message) if ZMQ::Util.resultcode_ok?(rc) puts "Message contained: #{received_message.copy_out_string}" else STDERR.puts "Error when receiving message: #{ZMQ::Util.error_string}" end
Define a custom layout for the data sent between 0mq peers.
class MyMessage class Layout < FFI::Struct layout :value1, :uint8, :value2, :uint64, :value3, :uint32, :value4, [:char, 30] end def initialize msg_struct = nil if msg_struct @msg_t = msg_struct @data = Layout.new(@msg_t.data) else @pointer = FFI::MemoryPointer.new :byte, Layout.size, true @data = Layout.new @pointer end end def size() @size = @msg_t.size; end def value1 @data[:value1] end def value4 @data[:value4].to_ptr.read_string end def value1=(val) @data[:value1] = val end def create_sendable_message msg = Message.new msg.copy_in_bytes @pointer, Layout.size end message = Message.new successful_read = socket.recv message message = MyMessage.new message if successful_read puts "value1 is #{message.value1}"
Public Class Methods
Recommended way to create a standard message. A Message object is returned upon success, nil when allocation fails.
# File lib/ffi-rzmq/message.rb, line 91 def self.create message = nil new(message) rescue nil end
# File lib/ffi-rzmq/message.rb, line 198 def self.msg_size() @msg_size; end
# File lib/ffi-rzmq/message.rb, line 95 def initialize message = nil # allocate our own pointer so that we can tell it to *not* zero out # the memory; it's pointless work since the library is going to # overwrite it anyway. @pointer = FFI::MemoryPointer.new Message.msg_size, 1, false if message copy_in_string message else # initialize an empty message structure to receive a message result_code = LibZMQ.zmq_msg_init @pointer raise unless Util.resultcode_ok?(result_code) end end
Public Instance Methods
Provides the memory address of the zmq_msg_t
struct. Used
mostly for passing to other methods accessing the underlying library that
require a real data address.
# File lib/ffi-rzmq/message.rb, line 141 def address @pointer end
Manually release the message struct and its associated data buffer.
Only releases the buffer a single time. Subsequent calls are no ops.
# File lib/ffi-rzmq/message.rb, line 183 def close rc = 0 if @pointer rc = LibZMQ.zmq_msg_close @pointer @pointer = nil end rc end
# File lib/ffi-rzmq/message.rb, line 146 def copy source LibZMQ.zmq_msg_copy @pointer, source end
Makes a copy of len
bytes from the ruby string
bytes
. Library handles deallocation of the native memory
buffer.
Can only be initialized via copy_in_string or copy_in_bytes once.
# File lib/ffi-rzmq/message.rb, line 126 def copy_in_bytes bytes, len data_buffer = LibC.malloc len # writes the exact number of bytes, no null byte to terminate string data_buffer.write_string bytes, len # use libC to call free on the data buffer; earlier versions used an # FFI::Function here that called back into Ruby, but Rubinius won't # support that and there are issues with the other runtimes too LibZMQ.zmq_msg_init_data @pointer, data_buffer, len, LibC::Free, nil end
Makes a copy of the ruby string
into a native memory buffer so
that libzmq can send it. The underlying library will handle deallocation of
the native memory buffer.
Can only be initialized via copy_in_string or copy_in_bytes once.
# File lib/ffi-rzmq/message.rb, line 116 def copy_in_string string string_size = string.respond_to?(:bytesize) ? string.bytesize : string.size copy_in_bytes string, string_size if string end
Returns the data buffer as a string.
Note: If this is binary data, it won't print very prettily.
# File lib/ffi-rzmq/message.rb, line 173 def copy_out_string data.read_string(size) end
Returns a pointer to the data buffer. This pointer should
never be freed. It will automatically be freed when the
message
object goes out of scope and gets garbage collected.
# File lib/ffi-rzmq/message.rb, line 165 def data LibZMQ.zmq_msg_data @pointer end
# File lib/ffi-rzmq/message.rb, line 203 def get(property) LibZMQ.zmq_msg_get(@pointer, property) end
Returns true if this message has additional parts coming.
# File lib/ffi-rzmq/message.rb, line 209 def more? Util.resultcode_ok?(get(MORE)) end
# File lib/ffi-rzmq/message.rb, line 150 def move source LibZMQ.zmq_msg_move @pointer, source end
# File lib/ffi-rzmq/message.rb, line 213 def set(property, value) LibZMQ.zmq_msg_set(@pointer, property, value) end
Provides the size of the data buffer for this zmq_msg_t
C
struct.
# File lib/ffi-rzmq/message.rb, line 156 def size LibZMQ.zmq_msg_size @pointer end