ffi-rxs 1.0.0 → 1.0.1
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/.gitignore +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +9 -0
- data/CHANGELOG +11 -0
- data/LICENSE +20 -0
- data/README.textile +86 -0
- data/examples/LICENSE +18 -0
- data/examples/README +2 -0
- data/examples/durable_pub.rb +34 -0
- data/examples/durable_sub.rb +29 -0
- data/examples/latency_measurement.rb +140 -0
- data/examples/reply.rb +25 -0
- data/examples/req_rep_poll.rb +71 -0
- data/examples/request.rb +24 -0
- data/examples/task_sink.rb +31 -0
- data/examples/task_vent.rb +34 -0
- data/examples/task_worker.rb +36 -0
- data/examples/throughput_measurement.rb +169 -0
- data/examples/weather_upd_client.rb +47 -0
- data/examples/weather_upd_server.rb +35 -0
- data/examples/xreq_xrep_poll.rb +101 -0
- data/ffi-rxs.gemspec +3 -5
- data/lib/ffi-rxs/constants.rb +15 -11
- data/lib/ffi-rxs/context.rb +54 -60
- data/lib/ffi-rxs/exceptions.rb +7 -5
- data/lib/ffi-rxs/libc.rb +1 -0
- data/lib/ffi-rxs/libxs.rb +2 -0
- data/lib/ffi-rxs/message.rb +79 -50
- data/lib/ffi-rxs/poll.rb +54 -12
- data/lib/ffi-rxs/poll_items.rb +2 -1
- data/lib/ffi-rxs/socket.rb +243 -184
- data/lib/ffi-rxs/util.rb +25 -16
- data/lib/ffi-rxs/version.rb +3 -1
- data/lib/ffi-rxs.rb +8 -14
- data/spec/socket_spec.rb +63 -0
- metadata +31 -19
- data/README.rdoc +0 -86
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
= Version 1.0.1
|
2
|
+
|
3
|
+
* Re-working of some ZeroMQ examples for use with Crossroads I/O
|
4
|
+
* Addition of missing socket option XS::IPV4ONLY
|
5
|
+
* Addition of new socket option XS::KEEPALIVE
|
6
|
+
* Editing of inline comments for Yard documentation in Textile
|
7
|
+
* Amended .gemspec to exclude ext/libxs.so from build to accommodate Travis CI in development
|
8
|
+
|
9
|
+
= Version 1.0.0
|
10
|
+
|
11
|
+
* Initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 - 2012 Chuck Remes, Chris Duncan and contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
'Software'), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
h1. About ffi-rxs
|
2
|
+
|
3
|
+
This gem wraps the "Crossroads I/O":http://crossroads.io networking library using the Ruby FFI (foreign function interface). It's a pure Ruby wrapper so this gem can be loaded and run by any Ruby runtime that supports FFI. That's all of them: MRI 1.9.x, Rubinius and JRuby.
|
4
|
+
|
5
|
+
Crossroads I/O is a fork of ZeroMQ. This gem is a re-working of the ffi-rzmq gem created by Chuck Remes to provide bindings for the Crossroads I/O libxs C library instead of the ZeroMQ libzmq library. The gem auto-configures itself to expose the API conforming to the loaded C library.
|
6
|
+
|
7
|
+
h2. Features/Problems
|
8
|
+
|
9
|
+
This gem needs to be tested in the wild. Please kick its tyres and give it a good thrashing. It is inevitable that bugs will be discovered, so please open issues for them here or fork this project, fix them, and send me a pull request.
|
10
|
+
|
11
|
+
The 'ffi' gem has dropped support for MRI 1.8.x. Since this project relies on that gem to load and run this code, then this project does not support MRI 1.8.x. I recommend JRuby for the best performance and stability.
|
12
|
+
|
13
|
+
h2. Requirements
|
14
|
+
|
15
|
+
* Crossroads I/O version 1.0.0 or later.
|
16
|
+
* ffi (>= 1.0.0)
|
17
|
+
|
18
|
+
The Crossroads I/O library must be installed on your system in a well-known location like /usr/local/lib. This is the default for new Crossroads I/O installs. Future releases may include the library as a C extension built at time of installation.
|
19
|
+
|
20
|
+
Do *not* run this gem under MRI with an old 'ffi' gem. It will crash randomly and you will be sad.
|
21
|
+
|
22
|
+
h2. Installation
|
23
|
+
|
24
|
+
A full gem has been released to Rubygems.org as of release 1.0.0. Make sure the Crossroads I/O library is already installed on your system.
|
25
|
+
|
26
|
+
* gem install ffi-rxs # should grab the latest release
|
27
|
+
|
28
|
+
|
29
|
+
To build from git master:
|
30
|
+
|
31
|
+
* git clone git://github.com/celldee/ffi-rxs
|
32
|
+
* cd ffi-rxs
|
33
|
+
* gem build ffi-rxs.gemspec
|
34
|
+
* gem install ffi-rxs-*.gem
|
35
|
+
|
36
|
+
|
37
|
+
*NOTE* for Windows users!
|
38
|
+
In order for this gem to find the libxs.dll, it *must* be on the Windows PATH. Google for "modify windows path" for instructions on how to do that if you are unfamiliar with that activity.
|
39
|
+
|
40
|
+
h2. Examples
|
41
|
+
|
42
|
+
h3. Using Request (REQ) socket -
|
43
|
+
|
44
|
+
<pre>
|
45
|
+
require 'ffi-rxs'
|
46
|
+
|
47
|
+
ctx = XS::Context.create()
|
48
|
+
socket = ctx.socket(XS::REQ)
|
49
|
+
socket.connect("tcp://127.0.0.1:5000")
|
50
|
+
|
51
|
+
for i in 1..10
|
52
|
+
msg = "msg #{i.to_s}"
|
53
|
+
socket.send_string(msg)
|
54
|
+
puts "Sending: " + msg
|
55
|
+
socket.recv_string(msg_in = '')
|
56
|
+
puts "Received: " + msg_in
|
57
|
+
end
|
58
|
+
</pre>
|
59
|
+
|
60
|
+
h3. Using Reply (REP) socket -
|
61
|
+
|
62
|
+
<pre>
|
63
|
+
require 'ffi-rxs'
|
64
|
+
|
65
|
+
ctx = XS::Context.create()
|
66
|
+
socket = ctx.socket(XS::REP)
|
67
|
+
socket.bind("tcp://127.0.0.1:5000")
|
68
|
+
|
69
|
+
while true do
|
70
|
+
socket.recv_string(msg = '')
|
71
|
+
puts "Got: " + msg
|
72
|
+
socket.send_string(msg)
|
73
|
+
end
|
74
|
+
</pre>
|
75
|
+
|
76
|
+
The above examples and additional ones are available in the repository examples folder.
|
77
|
+
|
78
|
+
h2. Links
|
79
|
+
|
80
|
+
* "Source code":http://github.com/celldee/ffi-rxs
|
81
|
+
* "Crossroads I/O website":http://crossroads.io
|
82
|
+
* "Crossroads I/O Discussion Group":http://groups.crossroads.io/
|
83
|
+
|
84
|
+
h2. License
|
85
|
+
|
86
|
+
This project is licensed under the MIT license. Please see the LICENSE file in the repository.
|
data/examples/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2010-2012 iMatix Corporation, Chris Duncan and Contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/examples/README
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Durable publisher to be used in conjunction with durable_sub.rb
|
4
|
+
# Justin Case <justin@playelite.com>
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
7
|
+
|
8
|
+
context = XS::Context.create()
|
9
|
+
|
10
|
+
# Subscriber tells us when it's ready here
|
11
|
+
sync = context.socket(XS::PULL)
|
12
|
+
sync.bind("tcp://127.0.0.1:5564")
|
13
|
+
|
14
|
+
# We send updates via this socket
|
15
|
+
publisher = context.socket(XS::PUB)
|
16
|
+
publisher.bind("tcp://127.0.0.1:5565")
|
17
|
+
|
18
|
+
# Wait for synchronization request
|
19
|
+
sync.recv_string(sync_request = '')
|
20
|
+
|
21
|
+
# Now broadcast exactly 10 updates with pause
|
22
|
+
10.times do |update_number|
|
23
|
+
message = sprintf("Update %d", update_number)
|
24
|
+
puts "Sending: " + message
|
25
|
+
publisher.send_string(message)
|
26
|
+
sleep(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
publisher.send_string("END")
|
30
|
+
|
31
|
+
sync.close
|
32
|
+
publisher.close
|
33
|
+
context.terminate
|
34
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Durable subscriber to be used in conjunction with durable_pub.rb
|
4
|
+
# Justin Case <justin@playelite.com>
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
7
|
+
|
8
|
+
context = XS::Context.create()
|
9
|
+
|
10
|
+
# Connect our subscriber socket
|
11
|
+
subscriber = context.socket(XS::SUB)
|
12
|
+
subscriber.setsockopt(XS::IDENTITY, "Hello")
|
13
|
+
subscriber.setsockopt(XS::SUBSCRIBE, "")
|
14
|
+
subscriber.connect("tcp://127.0.0.1:5565")
|
15
|
+
|
16
|
+
# Synchronize with publisher
|
17
|
+
sync = context.socket(XS::PUSH)
|
18
|
+
sync.connect("tcp://127.0.0.1:5564")
|
19
|
+
sync.send_string("")
|
20
|
+
|
21
|
+
# Get updates, exit when told to do so
|
22
|
+
loop do
|
23
|
+
subscriber.recv_string(message = '')
|
24
|
+
puts "Received: " + message
|
25
|
+
if message == "END"
|
26
|
+
break
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# latency_measurement.rb
|
4
|
+
|
5
|
+
# Within a single process, we start up two threads. One thread has a REQ (request)
|
6
|
+
# socket and the second thread has a REP (reply) socket. We measure the
|
7
|
+
# *round-trip* latency between these sockets. Only *one* message is in flight at
|
8
|
+
# any given moment.
|
9
|
+
#
|
10
|
+
# This example also illustrates how a single context can be shared amongst several
|
11
|
+
# threads. Sharing a single context also allows a user to specify the "inproc"
|
12
|
+
# transport in addition to "tcp" and "ipc".
|
13
|
+
#
|
14
|
+
# % ruby latency_measurement.rb tcp://127.0.0.1:5555 1024 1_000_000
|
15
|
+
#
|
16
|
+
# % ruby latency_measurement.rb inproc://lm_sock 1024 1_000_000
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
19
|
+
|
20
|
+
if ARGV.length < 3
|
21
|
+
puts "usage: ruby latency_measurement.rb <connect-to> <message-size> <roundtrip-count>"
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
link = ARGV[0]
|
26
|
+
message_size = ARGV[1].to_i
|
27
|
+
roundtrip_count = ARGV[2].to_i
|
28
|
+
|
29
|
+
def assert(rc)
|
30
|
+
raise "Last API call failed at #{caller(1)}" unless rc >= 0
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
master_context = XS::Context.new
|
35
|
+
rescue ContextError => e
|
36
|
+
STDERR.puts "Failed to allocate context or socket!"
|
37
|
+
raise
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class Receiver
|
42
|
+
def initialize context, link, size, count
|
43
|
+
@context = context
|
44
|
+
@link = link
|
45
|
+
@size = size
|
46
|
+
@count = count
|
47
|
+
|
48
|
+
begin
|
49
|
+
@socket = @context.socket(XS::REP)
|
50
|
+
rescue ContextError => e
|
51
|
+
STDERR.puts "Failed to allocate REP socket!"
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
|
55
|
+
assert(@socket.setsockopt(XS::LINGER, 100))
|
56
|
+
assert(@socket.setsockopt(XS::RCVHWM, 100))
|
57
|
+
assert(@socket.setsockopt(XS::SNDHWM, 100))
|
58
|
+
|
59
|
+
assert(@socket.bind(@link))
|
60
|
+
end
|
61
|
+
|
62
|
+
def run
|
63
|
+
@count.times do
|
64
|
+
string = ''
|
65
|
+
assert(@socket.recv_string(string, 0))
|
66
|
+
|
67
|
+
raise "Message size doesn't match, expected [#{@size}] but received [#{string.size}]" if @size != string.size
|
68
|
+
|
69
|
+
assert(@socket.send_string(string, 0))
|
70
|
+
end
|
71
|
+
|
72
|
+
assert(@socket.close)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Transmitter
|
77
|
+
def initialize context, link, size, count
|
78
|
+
@context = context
|
79
|
+
@link = link
|
80
|
+
@size = size
|
81
|
+
@count = count
|
82
|
+
|
83
|
+
begin
|
84
|
+
@socket = @context.socket(XS::REQ)
|
85
|
+
rescue ContextError => e
|
86
|
+
STDERR.puts "Failed to allocate REP socket!"
|
87
|
+
raise
|
88
|
+
end
|
89
|
+
|
90
|
+
assert(@socket.setsockopt(XS::LINGER, 100))
|
91
|
+
assert(@socket.setsockopt(XS::RCVHWM, 100))
|
92
|
+
assert(@socket.setsockopt(XS::SNDHWM, 100))
|
93
|
+
|
94
|
+
assert(@socket.connect(@link))
|
95
|
+
end
|
96
|
+
|
97
|
+
def run
|
98
|
+
msg = "#{ '3' * @size }"
|
99
|
+
|
100
|
+
elapsed = elapsed_microseconds do
|
101
|
+
@count.times do
|
102
|
+
assert(@socket.send_string(msg, 0))
|
103
|
+
assert(@socket.recv_string(msg, 0))
|
104
|
+
|
105
|
+
raise "Message size doesn't match, expected [#{@size}] but received [#{msg.size}]" if @size != msg.size
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
latency = elapsed / @count / 2
|
110
|
+
|
111
|
+
puts "message size: %i [B]" % @size
|
112
|
+
puts "roundtrip count: %i" % @count
|
113
|
+
puts "throughput (msgs/s): %i" % (@count / (elapsed / 1_000_000))
|
114
|
+
puts "mean latency: %.3f [us]" % latency
|
115
|
+
assert(@socket.close)
|
116
|
+
end
|
117
|
+
|
118
|
+
def elapsed_microseconds(&blk)
|
119
|
+
start = Time.now
|
120
|
+
yield
|
121
|
+
value = ((Time.now - start) * 1_000_000)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
threads = []
|
126
|
+
threads << Thread.new do
|
127
|
+
receiver = Receiver.new(master_context, link, message_size, roundtrip_count)
|
128
|
+
receiver.run
|
129
|
+
end
|
130
|
+
|
131
|
+
sleep 1
|
132
|
+
|
133
|
+
threads << Thread.new do
|
134
|
+
transmitter = Transmitter.new(master_context, link, message_size, roundtrip_count)
|
135
|
+
transmitter.run
|
136
|
+
end
|
137
|
+
|
138
|
+
threads.each {|t| t.join}
|
139
|
+
|
140
|
+
master_context.terminate
|
data/examples/reply.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# reply.rb
|
4
|
+
|
5
|
+
# This example is used in conjunction with request.rb. Run this program in
|
6
|
+
# a terminal/console window and then run request.rb in another terminal/console
|
7
|
+
# window and observe the output.
|
8
|
+
#
|
9
|
+
# Usage: ruby reply.rb
|
10
|
+
#
|
11
|
+
# To stop the program terminate the process with Ctrl-C or another
|
12
|
+
# method of your choice.
|
13
|
+
#
|
14
|
+
|
15
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
16
|
+
|
17
|
+
ctx = XS::Context.create()
|
18
|
+
socket = ctx.socket(XS::REP)
|
19
|
+
socket.bind("tcp://127.0.0.1:5000")
|
20
|
+
|
21
|
+
while true do
|
22
|
+
socket.recv_string(msg = '')
|
23
|
+
puts "Got: " + msg
|
24
|
+
socket.send_string(msg)
|
25
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# req_rep_poll.rb
|
4
|
+
#
|
5
|
+
# It illustrates the use of xs_poll(), as wrapped by the Ruby library,
|
6
|
+
# for detecting and responding to read and write events recorded on sockets.
|
7
|
+
# It also shows how to use XS::NO_BLOCK/XS::DONTWAIT for non-blocking send
|
8
|
+
# and receive.
|
9
|
+
|
10
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
11
|
+
|
12
|
+
|
13
|
+
def assert(rc)
|
14
|
+
raise "Last API call failed at #{caller(1)}" unless rc >= 0
|
15
|
+
end
|
16
|
+
|
17
|
+
link = "tcp://127.0.0.1:5554"
|
18
|
+
|
19
|
+
begin
|
20
|
+
ctx = XS::Context.create()
|
21
|
+
s1 = ctx.socket(XS::REQ)
|
22
|
+
s2 = ctx.socket(XS::REP)
|
23
|
+
rescue ContextError => e
|
24
|
+
STDERR.puts "Failed to allocate context or socket!"
|
25
|
+
raise
|
26
|
+
end
|
27
|
+
|
28
|
+
assert(s1.setsockopt(XS::LINGER, 100))
|
29
|
+
assert(s2.setsockopt(XS::LINGER, 100))
|
30
|
+
|
31
|
+
assert(s1.connect(link))
|
32
|
+
assert(s2.bind(link))
|
33
|
+
|
34
|
+
poller = XS::Poller.new
|
35
|
+
poller.register_readable(s2)
|
36
|
+
poller.register_writable(s1)
|
37
|
+
|
38
|
+
start_time = Time.now
|
39
|
+
@unsent = true
|
40
|
+
|
41
|
+
until @done do
|
42
|
+
assert(poller.poll_nonblock)
|
43
|
+
|
44
|
+
# send the message after 5 seconds
|
45
|
+
if Time.now - start_time > 5 && @unsent
|
46
|
+
payload = "#{ '3' * 1024 }"
|
47
|
+
|
48
|
+
puts "sending payload nonblocking"
|
49
|
+
assert(s1.send_string(payload, XS::NonBlocking))
|
50
|
+
@unsent = false
|
51
|
+
end
|
52
|
+
|
53
|
+
# check for messages after 1 second
|
54
|
+
if Time.now - start_time > 1
|
55
|
+
poller.readables.each do |sock|
|
56
|
+
received_msg = ''
|
57
|
+
assert(sock.recv_string(received_msg, XS::NonBlocking))
|
58
|
+
|
59
|
+
puts "message received [#{received_msg}]"
|
60
|
+
@done = true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
puts "executed in [#{Time.now - start_time}] seconds"
|
66
|
+
|
67
|
+
assert(s1.close)
|
68
|
+
assert(s2.close)
|
69
|
+
|
70
|
+
ctx.terminate
|
71
|
+
|
data/examples/request.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# request.rb
|
4
|
+
|
5
|
+
# This example is used in conjunction with reply.rb. Run this program in
|
6
|
+
# a terminal/console window and then run reply.rb in another terminal/console
|
7
|
+
# window and observe the output.
|
8
|
+
#
|
9
|
+
# Usage: ruby request.rb
|
10
|
+
#
|
11
|
+
|
12
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
13
|
+
|
14
|
+
ctx = XS::Context.create()
|
15
|
+
socket = ctx.socket(XS::REQ)
|
16
|
+
socket.connect("tcp://127.0.0.1:5000")
|
17
|
+
|
18
|
+
for i in 1..10
|
19
|
+
msg = "msg #{i.to_s}"
|
20
|
+
socket.send_string(msg)
|
21
|
+
puts "Sending: " + msg
|
22
|
+
socket.recv_string(msg_in = '')
|
23
|
+
puts "Received: " + msg_in
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Task sink to be used in conjunction with task_vent.rb
|
4
|
+
# and task_worker.rb
|
5
|
+
# Binds PULL socket to tcp://localhost:5558
|
6
|
+
# Collects results from task_workers via that socket
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
9
|
+
|
10
|
+
# Prepare our context and socket
|
11
|
+
context = XS::Context.create()
|
12
|
+
receiver = context.socket(XS::PULL)
|
13
|
+
receiver.bind("tcp://*:5558")
|
14
|
+
|
15
|
+
# Wait for start of batch
|
16
|
+
receiver.recv_string('')
|
17
|
+
puts 'Sink started'
|
18
|
+
tstart = Time.now
|
19
|
+
|
20
|
+
# Process 100 confirmations
|
21
|
+
100.times do |task_nbr|
|
22
|
+
receiver.recv_string('')
|
23
|
+
$stdout << ((task_nbr % 10 == 0) ? ':' : '.')
|
24
|
+
$stdout.flush
|
25
|
+
end
|
26
|
+
|
27
|
+
# Calculate and report duration of batch
|
28
|
+
tend = Time.now
|
29
|
+
total_msec = (tend-tstart) * 1000
|
30
|
+
puts "Total elapsed time: #{total_msec} msec"
|
31
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Task vent to be used in conjunction with task_worker.rb
|
4
|
+
# and task_sink.rb
|
5
|
+
# Binds PUSH socket to tcp://localhost:5557
|
6
|
+
# Sends batch of tasks to task_workers via that socket
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
9
|
+
|
10
|
+
context = XS::Context.create()
|
11
|
+
|
12
|
+
# Socket to send messages on
|
13
|
+
sender = context.socket(XS::PUSH)
|
14
|
+
sender.bind("tcp://*:5557")
|
15
|
+
|
16
|
+
puts "Press enter when the workers are ready..."
|
17
|
+
$stdin.read(1)
|
18
|
+
puts "Sending tasks to workers..."
|
19
|
+
|
20
|
+
# The first message is "0" and signals start of batch
|
21
|
+
sender.send_string('0')
|
22
|
+
|
23
|
+
# Send 100 tasks
|
24
|
+
total_msec = 0 # Total expected cost in msecs
|
25
|
+
100.times do
|
26
|
+
workload = rand(100) + 1
|
27
|
+
total_msec += workload
|
28
|
+
$stdout << "#{workload}."
|
29
|
+
sender.send_string(workload.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
puts "Total expected cost: #{total_msec} msec"
|
33
|
+
Kernel.sleep(1) # Give Crossroads time to deliver
|
34
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Task worker to be used in conjunction with task_vent.rb
|
4
|
+
# and task_sink.rb
|
5
|
+
# Connects PULL socket to tcp://localhost:5557
|
6
|
+
# Collects workloads from task_vent via that socket
|
7
|
+
# Connects PUSH socket to tcp://localhost:5558
|
8
|
+
# Sends results to sink via that socket
|
9
|
+
|
10
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ffi-rxs')
|
11
|
+
|
12
|
+
context = XS::Context.create()
|
13
|
+
|
14
|
+
# Socket to receive messages on
|
15
|
+
receiver = context.socket(XS::PULL)
|
16
|
+
receiver.connect("tcp://localhost:5557")
|
17
|
+
|
18
|
+
# Socket to send messages to
|
19
|
+
sender = context.socket(XS::PUSH)
|
20
|
+
sender.connect("tcp://localhost:5558")
|
21
|
+
|
22
|
+
# Process tasks forever
|
23
|
+
while true
|
24
|
+
|
25
|
+
receiver.recv_string(msec = '')
|
26
|
+
# Simple progress indicator for the viewer
|
27
|
+
$stdout << "#{msec}."
|
28
|
+
$stdout.flush
|
29
|
+
|
30
|
+
# Do the work
|
31
|
+
sleep(msec.to_f / 1000)
|
32
|
+
|
33
|
+
# Send results to sink
|
34
|
+
sender.send_string("")
|
35
|
+
end
|
36
|
+
|