ffi-rzmq 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS.txt +1 -0
- data/History.txt +35 -0
- data/README.rdoc +48 -15
- data/Rakefile +7 -2
- data/examples/README.rdoc +21 -76
- data/examples/{local_lat.rb → v2api/local_lat.rb} +27 -12
- data/examples/v2api/local_lat_poll.rb +66 -0
- data/examples/{local_throughput.rb → v2api/local_throughput.rb} +24 -9
- data/examples/v2api/publish_subscribe.rb +82 -0
- data/examples/{remote_lat.rb → v2api/remote_lat.rb} +26 -8
- data/examples/v2api/remote_throughput.rb +39 -0
- data/examples/v2api/reqrep_poll.rb +62 -0
- data/examples/v2api/request_response.rb +40 -0
- data/examples/v2api/throughput_measurement.rb +138 -0
- data/examples/v3api/local_lat.rb +59 -0
- data/examples/v3api/local_lat_poll.rb +66 -0
- data/examples/v3api/local_throughput.rb +65 -0
- data/examples/v3api/publish_subscribe.rb +82 -0
- data/examples/v3api/remote_lat.rb +71 -0
- data/examples/v3api/remote_throughput.rb +47 -0
- data/examples/v3api/reqrep_poll.rb +62 -0
- data/examples/v3api/request_response.rb +40 -0
- data/examples/v3api/throughput_measurement.rb +166 -0
- data/ext/README +5 -0
- data/ffi-rzmq.gemspec +4 -4
- data/lib/ffi-rzmq.rb +4 -1
- data/lib/ffi-rzmq/constants.rb +178 -0
- data/lib/ffi-rzmq/context.rb +61 -45
- data/lib/ffi-rzmq/device.rb +22 -9
- data/lib/ffi-rzmq/exceptions.rb +0 -98
- data/lib/ffi-rzmq/libc.rb +19 -0
- data/lib/ffi-rzmq/libzmq.rb +188 -0
- data/lib/ffi-rzmq/message.rb +33 -40
- data/lib/ffi-rzmq/poll.rb +49 -52
- data/lib/ffi-rzmq/socket.rb +902 -392
- data/lib/ffi-rzmq/util.rb +101 -0
- data/spec/context_spec.rb +47 -21
- data/spec/device_spec.rb +78 -58
- data/spec/message_spec.rb +90 -12
- data/spec/multipart_spec.rb +162 -0
- data/spec/nonblocking_recv_spec.rb +325 -0
- data/spec/pushpull_spec.rb +95 -34
- data/spec/reqrep_spec.rb +55 -20
- data/spec/socket_spec.rb +353 -204
- data/spec/spec_helper.rb +46 -3
- data/version.txt +1 -1
- metadata +91 -66
- data/examples/local_lat_poll.rb +0 -54
- data/examples/local_lat_zerocopy.rb +0 -24
- data/examples/publish_subscribe.rb +0 -52
- data/examples/remote_lat_zerocopy.rb +0 -35
- data/examples/remote_throughput.rb +0 -27
- data/examples/reqrep_poll.rb +0 -49
- data/examples/request_response.rb +0 -23
- data/lib/ffi-rzmq/wrapper.rb +0 -121
- data/lib/ffi-rzmq/zmq.rb +0 -198
data/examples/reqrep_poll.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'ffi-rzmq'
|
3
|
-
|
4
|
-
|
5
|
-
link = "tcp://127.0.0.1:5554"
|
6
|
-
|
7
|
-
ctx = ZMQ::Context.new 1
|
8
|
-
s1 = ctx.socket ZMQ::REQ
|
9
|
-
s2 = ctx.socket ZMQ::REP
|
10
|
-
|
11
|
-
s1.connect link
|
12
|
-
s2.bind link
|
13
|
-
|
14
|
-
poller = ZMQ::Poller.new
|
15
|
-
poller.register_readable s2
|
16
|
-
poller.register_writable s1
|
17
|
-
|
18
|
-
start_time = Time.now
|
19
|
-
@unsent = true
|
20
|
-
|
21
|
-
until @done do
|
22
|
-
begin
|
23
|
-
poller.poll_nonblock
|
24
|
-
rescue ZMQ::PollError => e
|
25
|
-
puts "efault? [#{e.efault?}]"
|
26
|
-
raise
|
27
|
-
end
|
28
|
-
|
29
|
-
# send the message after 5 seconds
|
30
|
-
if Time.now - start_time > 5 && @unsent
|
31
|
-
payload = "#{ '3' * 1024 }"
|
32
|
-
|
33
|
-
puts "sending payload nonblocking"
|
34
|
-
s1.send_string payload, ZMQ::NOBLOCK
|
35
|
-
@unsent = false
|
36
|
-
end
|
37
|
-
|
38
|
-
# check for messages after 1 second
|
39
|
-
if Time.now - start_time > 1
|
40
|
-
poller.readables.each do |sock|
|
41
|
-
received_msg = sock.recv_string ZMQ::NOBLOCK
|
42
|
-
|
43
|
-
puts "message received [#{received_msg}]"
|
44
|
-
@done = true
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
puts "executed in [#{Time.now - start_time}] seconds"
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'ffi-rzmq'
|
3
|
-
|
4
|
-
|
5
|
-
link = "tcp://127.0.0.1:5555"
|
6
|
-
|
7
|
-
ctx = ZMQ::Context.new 1
|
8
|
-
s1 = ctx.socket ZMQ::REQ
|
9
|
-
s2 = ctx.socket ZMQ::REP
|
10
|
-
|
11
|
-
s2.bind link
|
12
|
-
s1.connect link
|
13
|
-
|
14
|
-
payload = "#{ '3' * 2048 }"
|
15
|
-
sent_msg = ZMQ::Message.new payload
|
16
|
-
received_msg = ZMQ::Message.new
|
17
|
-
|
18
|
-
s1.send sent_msg
|
19
|
-
s2.recv received_msg
|
20
|
-
|
21
|
-
result = payload == received_msg.copy_out_string ? "Request received" : "Received wrong payload"
|
22
|
-
|
23
|
-
p result
|
data/lib/ffi-rzmq/wrapper.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
require 'ffi' unless RBX # external gem
|
2
|
-
|
3
|
-
module LibC
|
4
|
-
extend FFI::Library
|
5
|
-
# figures out the correct libc for each platform including Windows
|
6
|
-
library = ffi_lib(FFI::Library::LIBC).first
|
7
|
-
|
8
|
-
# Size_t not working properly on Windows
|
9
|
-
find_type(:size_t) rescue typedef(:ulong, :size_t)
|
10
|
-
|
11
|
-
# memory allocators
|
12
|
-
attach_function :malloc, [:size_t], :pointer
|
13
|
-
attach_function :free, [:pointer], :void
|
14
|
-
|
15
|
-
# get a pointer to the free function; used for ZMQ::Message deallocation
|
16
|
-
Free = library.find_symbol('free')
|
17
|
-
|
18
|
-
# memory movers
|
19
|
-
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
|
20
|
-
end # module LibC
|
21
|
-
|
22
|
-
module LibZMQ
|
23
|
-
extend FFI::Library
|
24
|
-
ZMQ_LIB_PATHS = %w{/usr/local/lib /opt/local/lib /usr/local/homebrew/lib}.map{|path| "#{path}/libzmq.#{FFI::Platform::LIBSUFFIX}"}
|
25
|
-
ffi_lib(%w{libzmq} + ZMQ_LIB_PATHS)
|
26
|
-
|
27
|
-
# Size_t not working properly on Windows
|
28
|
-
find_type(:size_t) rescue typedef(:ulong, :size_t)
|
29
|
-
|
30
|
-
# Misc
|
31
|
-
attach_function :zmq_version, [:pointer, :pointer, :pointer], :void
|
32
|
-
|
33
|
-
# Context and misc api
|
34
|
-
attach_function :zmq_init, [:int], :pointer
|
35
|
-
attach_function :zmq_socket, [:pointer, :int], :pointer
|
36
|
-
attach_function :zmq_term, [:pointer], :int
|
37
|
-
attach_function :zmq_errno, [], :int
|
38
|
-
attach_function :zmq_strerror, [:int], :pointer
|
39
|
-
|
40
|
-
# Message api
|
41
|
-
attach_function :zmq_msg_init, [:pointer], :int
|
42
|
-
attach_function :zmq_msg_init_size, [:pointer, :size_t], :int
|
43
|
-
attach_function :zmq_msg_init_data, [:pointer, :pointer, :size_t, :pointer, :pointer], :int
|
44
|
-
attach_function :zmq_msg_close, [:pointer], :int
|
45
|
-
attach_function :zmq_msg_data, [:pointer], :pointer
|
46
|
-
attach_function :zmq_msg_size, [:pointer], :size_t
|
47
|
-
attach_function :zmq_msg_copy, [:pointer, :pointer], :int
|
48
|
-
attach_function :zmq_msg_move, [:pointer, :pointer], :int
|
49
|
-
|
50
|
-
|
51
|
-
# Used for casting pointers back to the struct
|
52
|
-
class Msg < FFI::Struct
|
53
|
-
layout :content, :pointer,
|
54
|
-
:flags, :uint8,
|
55
|
-
:vsm_size, :uint8,
|
56
|
-
:vsm_data, [:uint8, 30]
|
57
|
-
end # class Msg
|
58
|
-
|
59
|
-
|
60
|
-
# Socket api
|
61
|
-
# @blocking = true is a hint to FFI that the following (and only the following)
|
62
|
-
# function may block, therefore it should release the GIL before calling it.
|
63
|
-
# This can aid in situations where the function call will/may block and another
|
64
|
-
# thread within the lib may try to call back into the ruby runtime. Failure to
|
65
|
-
# release the GIL will result in a hang; the hint *may* allow things to run
|
66
|
-
# smoothly for Ruby runtimes hampered by a GIL.
|
67
|
-
#
|
68
|
-
# This is really only honored by the MRI implementation.
|
69
|
-
attach_function :zmq_setsockopt, [:pointer, :int, :pointer, :int], :int
|
70
|
-
attach_function :zmq_getsockopt, [:pointer, :int, :pointer, :pointer], :int
|
71
|
-
attach_function :zmq_bind, [:pointer, :string], :int
|
72
|
-
attach_function :zmq_connect, [:pointer, :string], :int
|
73
|
-
@blocking = true
|
74
|
-
attach_function :zmq_send, [:pointer, :pointer, :int], :int
|
75
|
-
@blocking = true
|
76
|
-
attach_function :zmq_recv, [:pointer, :pointer, :int], :int
|
77
|
-
attach_function :zmq_close, [:pointer], :int
|
78
|
-
|
79
|
-
@blocking = true
|
80
|
-
attach_function :zmq_device, [:int, :pointer, :pointer], :int
|
81
|
-
|
82
|
-
# Poll api
|
83
|
-
@blocking = true
|
84
|
-
attach_function :zmq_poll, [:pointer, :int, :long], :int
|
85
|
-
|
86
|
-
module PollItemLayout
|
87
|
-
def self.included(base)
|
88
|
-
base.class_eval do
|
89
|
-
layout :socket, :pointer,
|
90
|
-
:fd, :int,
|
91
|
-
:events, :short,
|
92
|
-
:revents, :short
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end # module PollItemLayout
|
96
|
-
|
97
|
-
class PollItem < FFI::Struct
|
98
|
-
include PollItemLayout
|
99
|
-
|
100
|
-
def socket() self[:socket]; end
|
101
|
-
|
102
|
-
def readable?
|
103
|
-
(self[:revents] & ZMQ::POLLIN) > 0
|
104
|
-
end
|
105
|
-
|
106
|
-
def writable?
|
107
|
-
(self[:revents] & ZMQ::POLLOUT) > 0
|
108
|
-
end
|
109
|
-
|
110
|
-
def both_accessible?
|
111
|
-
readable? && writable?
|
112
|
-
end
|
113
|
-
|
114
|
-
def inspect
|
115
|
-
"socket [#{socket}], fd [#{self[:fd]}], events [#{self[:events]}], revents [#{self[:revents]}]"
|
116
|
-
end
|
117
|
-
|
118
|
-
def to_s; inspect; end
|
119
|
-
end # class PollItem
|
120
|
-
|
121
|
-
end # module LibZMQ
|
data/lib/ffi-rzmq/zmq.rb
DELETED
@@ -1,198 +0,0 @@
|
|
1
|
-
module ZMQ
|
2
|
-
|
3
|
-
# Socket types
|
4
|
-
PAIR = 0
|
5
|
-
PUB = 1
|
6
|
-
SUB = 2
|
7
|
-
REQ = 3
|
8
|
-
REP = 4
|
9
|
-
DEALER = XREQ = 5
|
10
|
-
ROUTER = XREP = 6
|
11
|
-
PULL = UPSTREAM = 7
|
12
|
-
PUSH = DOWNSTREAM = 8
|
13
|
-
|
14
|
-
SocketTypeNameMap = {
|
15
|
-
PAIR => "PAIR",
|
16
|
-
PUB => "PUB",
|
17
|
-
SUB => "SUB",
|
18
|
-
REQ => "REQ",
|
19
|
-
REP => "REP",
|
20
|
-
ROUTER => "ROUTER",
|
21
|
-
DEALER => "DEALER",
|
22
|
-
PULL => "PULL",
|
23
|
-
PUSH => "PUSH"
|
24
|
-
}
|
25
|
-
|
26
|
-
# Socket options
|
27
|
-
HWM = 1
|
28
|
-
SWAP = 3
|
29
|
-
AFFINITY = 4
|
30
|
-
IDENTITY = 5
|
31
|
-
SUBSCRIBE = 6
|
32
|
-
UNSUBSCRIBE = 7
|
33
|
-
RATE = 8
|
34
|
-
RECOVERY_IVL = 9
|
35
|
-
MCAST_LOOP = 10
|
36
|
-
SNDBUF = 11
|
37
|
-
RCVBUF = 12
|
38
|
-
RCVMORE = 13
|
39
|
-
FD = 14
|
40
|
-
EVENTS = 15
|
41
|
-
TYPE = 16
|
42
|
-
LINGER = 17
|
43
|
-
RECONNECT_IVL = 18
|
44
|
-
BACKLOG = 19
|
45
|
-
RECOVERY_IVL_MSEC = 20
|
46
|
-
|
47
|
-
# Send/recv options
|
48
|
-
NOBLOCK = 1
|
49
|
-
SNDMORE = 2
|
50
|
-
|
51
|
-
# I/O multiplexing
|
52
|
-
|
53
|
-
POLL = 1
|
54
|
-
POLLIN = 1
|
55
|
-
POLLOUT = 2
|
56
|
-
POLLERR = 4
|
57
|
-
|
58
|
-
# Socket errors
|
59
|
-
EAGAIN = Errno::EAGAIN::Errno
|
60
|
-
EINVAL = Errno::EINVAL::Errno
|
61
|
-
ENOMEM = Errno::ENOMEM::Errno
|
62
|
-
ENODEV = Errno::ENODEV::Errno
|
63
|
-
EFAULT = Errno::EFAULT::Errno
|
64
|
-
|
65
|
-
# Device Types
|
66
|
-
STREAMER = 1
|
67
|
-
FORWARDER = 2
|
68
|
-
QUEUE = 3
|
69
|
-
|
70
|
-
# ZMQ errors
|
71
|
-
HAUSNUMERO = 156384712
|
72
|
-
EMTHREAD = (HAUSNUMERO + 50)
|
73
|
-
EFSM = (HAUSNUMERO + 51)
|
74
|
-
ENOCOMPATPROTO = (HAUSNUMERO + 52)
|
75
|
-
ETERM = (HAUSNUMERO + 53)
|
76
|
-
|
77
|
-
# Rescue unknown constants and use the ZeroMQ defined values
|
78
|
-
# Usually only happens on Windows though some don't resolve on
|
79
|
-
# OSX too (ENOTSUP)
|
80
|
-
ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
|
81
|
-
EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
|
82
|
-
ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
|
83
|
-
ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
|
84
|
-
EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
|
85
|
-
EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
|
86
|
-
ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
|
87
|
-
EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# These methods don't belong to any specific context. They get included
|
92
|
-
# in the #Context, #Socket and #Poller classes.
|
93
|
-
#
|
94
|
-
module Util
|
95
|
-
|
96
|
-
# Returns the +errno+ as set by the libzmq library.
|
97
|
-
#
|
98
|
-
def errno
|
99
|
-
LibZMQ.zmq_errno
|
100
|
-
end
|
101
|
-
|
102
|
-
# Returns a string corresponding to the currently set #errno. These
|
103
|
-
# error strings are defined by libzmq.
|
104
|
-
#
|
105
|
-
def error_string
|
106
|
-
LibZMQ.zmq_strerror(errno).read_string
|
107
|
-
end
|
108
|
-
|
109
|
-
# Returns an array of the form [major, minor, patch] to represent the
|
110
|
-
# version of libzmq.
|
111
|
-
#
|
112
|
-
# Class method! Invoke as: ZMQ::Util.version
|
113
|
-
#
|
114
|
-
def self.version
|
115
|
-
major = FFI::MemoryPointer.new :int
|
116
|
-
minor = FFI::MemoryPointer.new :int
|
117
|
-
patch = FFI::MemoryPointer.new :int
|
118
|
-
LibZMQ.zmq_version major, minor, patch
|
119
|
-
[major.read_int, minor.read_int, patch.read_int]
|
120
|
-
end
|
121
|
-
|
122
|
-
# Compares the 0mq library API version to a minimal version tuple. Returns
|
123
|
-
# true if it meets the minimum requirement, false otherwise.
|
124
|
-
#
|
125
|
-
# Takes a +tuple+ with 3 elements corresponding to the major, minor and patch
|
126
|
-
# version levels.
|
127
|
-
#
|
128
|
-
# e.g. Util.minimum_api?([2, 1, 0])
|
129
|
-
#
|
130
|
-
def self.minimum_api? tuple
|
131
|
-
api_version = Util.version
|
132
|
-
|
133
|
-
# call #to_i to convert nil entries to 0 so the comparison is valid
|
134
|
-
result = tuple[0].to_i <= api_version[0] &&
|
135
|
-
tuple[1].to_i <= api_version[1] &&
|
136
|
-
tuple[2].to_i <= api_version[2]
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
private
|
141
|
-
|
142
|
-
# :doc:
|
143
|
-
# Called by most library methods to verify there were no errors during
|
144
|
-
# operation. If any are found, raise the appropriate #ZeroMQError.
|
145
|
-
#
|
146
|
-
# When no error is found, this method returns +true+ which is behavior
|
147
|
-
# used internally by #send and #recv.
|
148
|
-
#
|
149
|
-
def error_check source, result_code
|
150
|
-
unless result_code.zero?
|
151
|
-
raise_error source, result_code
|
152
|
-
end
|
153
|
-
|
154
|
-
# used by Socket::send/recv, ignored by others
|
155
|
-
true
|
156
|
-
end
|
157
|
-
|
158
|
-
# :doc:
|
159
|
-
# Only called on sockets in non-blocking mode.
|
160
|
-
#
|
161
|
-
# Checks the #errno and +result_code+ values for a failed non-blocking
|
162
|
-
# send/recv. True only when #errno is EGAIN and +result_code+ is non-zero.
|
163
|
-
#
|
164
|
-
def error_check_nonblock result_code
|
165
|
-
if result_code.zero?
|
166
|
-
true
|
167
|
-
else
|
168
|
-
# need to check result_code again because !eagain? could be true
|
169
|
-
# and we need the result_code test to fail again to give the right result
|
170
|
-
# !eagain? is true, result_code is -1 => return false
|
171
|
-
# !eagain? is false, result_code is -1 => return false
|
172
|
-
!eagain? && result_code.zero?
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def raise_error source, result_code
|
177
|
-
case source
|
178
|
-
when ZMQ_SEND_STR, ZMQ_RECV_STR, ZMQ_SOCKET_STR, ZMQ_SETSOCKOPT_STR, ZMQ_GETSOCKOPT_STR, ZMQ_BIND_STR, ZMQ_CONNECT_STR, ZMQ_CLOSE_STR
|
179
|
-
raise SocketError.new source, result_code, errno, error_string
|
180
|
-
when ZMQ_INIT_STR, ZMQ_TERM_STR
|
181
|
-
raise ContextError.new source, result_code, errno, error_string
|
182
|
-
when ZMQ_POLL_STR
|
183
|
-
raise PollError.new source, result_code, errno, error_string
|
184
|
-
when ZMQ_MSG_INIT_STR, ZMQ_MSG_INIT_DATA_STR, ZMQ_MSG_COPY_STR, ZMQ_MSG_MOVE_STR
|
185
|
-
raise MessageError.new source, result_code, errno, error_string
|
186
|
-
else
|
187
|
-
raise ZeroMQError.new source, result_code, -1,
|
188
|
-
"Source [#{source}] does not match any zmq_* strings, rc [#{result_code}], errno [#{errno}], error_string [#{error_string}]"
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
def eagain?
|
193
|
-
EAGAIN == errno
|
194
|
-
end
|
195
|
-
|
196
|
-
end # module Util
|
197
|
-
|
198
|
-
end # module ZMQ
|