simple_ipc 1.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.
Files changed (4) hide show
  1. data/README.md +29 -0
  2. data/lib/simple_ipc.rb +234 -0
  3. data/test/test.rb +8 -0
  4. metadata +66 -0
@@ -0,0 +1,29 @@
1
+ SimpleIPC
2
+ =========
3
+
4
+ Description
5
+ -----------
6
+
7
+ SimpleIPC is a library for doing simple inter-process communication in Ruby.
8
+
9
+ Example
10
+ -------
11
+
12
+ Server example:
13
+
14
+ from_client = SimpleIPC::IPC.new :port => 5000, :nonblock => true, :kind => :unix
15
+ from_client.listen
16
+ running = true
17
+ while running != "stop" do
18
+ running = from_client.get
19
+ p running if running
20
+ sleep 0.01
21
+ end
22
+
23
+
24
+ Client example:
25
+
26
+ to_server = SimpleIPC::IPC.new :kind => :unix
27
+ to_server.send([1,2,3, "test"])
28
+ to_server.send({:a => "test", :b => "prova"})
29
+ to_server.send("stop")
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env ruby
2
+ # simple_ipc
3
+ #
4
+ # Created by Paolo Bosetti on 2011-01-18.
5
+ # Copyright (c) 2011 University of Trento. All rights reserved.
6
+ #
7
+
8
+ require "yaml"
9
+ require "socket"
10
+ require "timeout"
11
+ require "fileutils"
12
+
13
+
14
+ # SimpleIPC implements a simple inter process communication
15
+ # @author Paolo Bosetti
16
+ module SimpleIPC
17
+ VERSION = "1.1"
18
+ LOCALHOST = "127.0.0.1"
19
+ BROADCAST = "" # Accept connections from INADDR_ANY
20
+ LENGTH_CODE = 'N'
21
+ LENGTH_SIZE = [0].pack(LENGTH_CODE).size
22
+
23
+ def SimpleIPC.version; VERSION; end
24
+
25
+ # Wrapper class exposing the same API for +UNIXSocket+ and +UDPSocket+ classes.
26
+ class Socket
27
+
28
+ # Default initialization hash is:
29
+ # {
30
+ # :port => 5000, # port, only used for UDPSockets
31
+ # :host => LOCALHOST, # Host to talk with, only used for UDPSockets
32
+ # :kind => :unix, # kind of socket, either :unix or :udp
33
+ # :force => true # if true, force removing of stale socket files
34
+ # }
35
+ # @param [Hash] args a hash of config values
36
+ def initialize(args = {})
37
+ @cfg = {
38
+ :port => 5000,
39
+ :host => LOCALHOST,
40
+ :kind => :unix,
41
+ :force => true
42
+ }
43
+ @cfg.merge! args
44
+ case @cfg[:kind]
45
+ when :unix
46
+ @socket_file = "/tmp/#{$0}.sok"
47
+ @socket = nil
48
+ when :udp
49
+ @socket = UDPSocket.new
50
+ else
51
+ raise ArgumentError, "Either :unix or :udp allowed"
52
+ end
53
+ @open = false
54
+ end
55
+
56
+ # Opens the connection. Only has to be called once before sending messages.
57
+ # Only used for client sockets.
58
+ def connect
59
+ return false if @open
60
+ case @cfg[:kind]
61
+ when :unix
62
+ @socket = UNIXSocket.open(@socket_file)
63
+ when :udp
64
+ @socket.connect(@cfg[:host], @cfg[:port])
65
+ end
66
+ @open = true
67
+ end
68
+
69
+ # Sends a +String+ through the socket.
70
+ # @param [String] string the message to be sent
71
+ def print(string)
72
+ @socket.print(string)
73
+ end
74
+
75
+ # Listens for incoming messages, i.e. becomes a server. If +@cfg[:force]+
76
+ # is true, it also silently removes any existing stale socket file, otherwise
77
+ # stops.
78
+ # @raise [Errno::EADDRINUSE] when +@cfg[:force]+ is false and a socket file
79
+ # already exists
80
+ def listen
81
+ case @cfg[:kind]
82
+ when :unix
83
+ @socket = UNIXServer.open(@socket_file).accept
84
+ when :udp
85
+ @socket.bind(BROADCAST, @cfg[:port])
86
+ end
87
+ rescue Errno::EADDRINUSE
88
+ if @cfg[:force] then
89
+ FileUtils::rm(@socket_file)
90
+ retry
91
+ else
92
+ raise Errno::EADDRINUSE, $!
93
+ end
94
+ end
95
+
96
+ # Receives a message of length +bytes+.
97
+ # @param [Integer] bytes the number of characters to be read
98
+ # @return [String]
99
+ def recvfrom(bytes)
100
+ @socket.recvfrom(bytes)
101
+ end
102
+
103
+ # Receives a message of length +bytes+ in non-blocking way.
104
+ # @param [Integer] bytes the number of characters to be read
105
+ # @return [String]
106
+ def recv_nonblock(bytes)
107
+ @socket.recv_nonblock(bytes)
108
+ end
109
+
110
+ # Closes the socket and removes the socket file if it exists.
111
+ def close
112
+ @socket.close
113
+ @open = false
114
+ FileUtils::rm(@socket_file) if @socket_file
115
+ end
116
+
117
+ end #Socket Class
118
+
119
+ class IPC
120
+ attr_accessor :cfg
121
+
122
+ # Default initialization hash is:
123
+ # {:port => 5000, # Port to listen at
124
+ # :host => LOCALHOST, # Host to talk to
125
+ # :timeout => 0, # Timeout for blocking connections
126
+ # :blocking => false} # use blocking read
127
+ # @param [Hash] args a hash of config values
128
+ def initialize(args = {})
129
+ raise ArgumentError, "expecting an Hash" unless args.kind_of? Hash
130
+ @cfg = {:port => 5000, :host => LOCALHOST, :timeout => 0}
131
+ @cfg.merge! args
132
+ @socket = Socket.new @cfg
133
+ end
134
+
135
+ # Sends a general object to the server. If an optional block is given, then it
136
+ # is used to perform the object serialization. Otherwise, YAML#dump is used
137
+ # for serialization.
138
+ # @param [Object] something an object
139
+ # @yield [Object] a block that serializes the received +Object+
140
+ def send(something)
141
+ if block_given? then
142
+ payload = yield(something)
143
+ else
144
+ payload = YAML.dump(something)
145
+ end
146
+ length = [payload.size].pack(LENGTH_CODE)
147
+ @socket.connect
148
+ @socket.print length
149
+ @socket.print payload
150
+ return payload
151
+ end
152
+
153
+ # Puts the object in listening state (becomes a server).
154
+ def listen
155
+ @socket.listen
156
+ end
157
+
158
+ # Gets an object (only valid if it is a server). An optional block can be
159
+ # given for parsing the received +String+. If no block is given, then the
160
+ # YAML#load deserialization is automatically used.
161
+ # @return [Object] a parsed object
162
+ # @yield [String] a block that deserializes the received +String+
163
+ def get
164
+ result = nil
165
+ begin
166
+ if @cfg[:timeout] > 0 and !@cfg[:nonblock] then
167
+ Timeout::timeout(@cfg[:timeout]) do |to|
168
+ result = get_
169
+ end
170
+ else
171
+ result = get_
172
+ end
173
+ rescue Timeout::Error
174
+ result = nil
175
+ rescue Errno::EAGAIN
176
+ return nil
177
+ end
178
+
179
+ if block_given? then
180
+ return yield(result)
181
+ else
182
+ return YAML.load(result)
183
+ end
184
+ end
185
+
186
+ # Closes the socket.
187
+ def close
188
+ @socket.close
189
+ end
190
+
191
+ private
192
+ def get_
193
+ if @cfg[:nonblock] then
194
+ msg, sender = @socket.recv_nonblock(LENGTH_SIZE)
195
+ else
196
+ msg = @socket.recvfrom(LENGTH_SIZE)[0]
197
+ end
198
+ length = msg.unpack(LENGTH_CODE)[0]
199
+ msg, sender = @socket.recvfrom(length)
200
+ return msg
201
+ end
202
+
203
+ end #IPC Class
204
+ end #SimpleIPC module
205
+
206
+ if $0 == __FILE__ then
207
+ puts "Using SimpleIPC version #{SimpleIPC::version}"
208
+ ary = [1,2,3,4]
209
+ if ARGV[0] == "server" then
210
+ from_client = SimpleIPC::IPC.new :port => 5000, :nonblock => true, :kind => :udp
211
+ from_client.listen
212
+ running = true
213
+ while running != "stop" do
214
+ running = from_client.get
215
+ p running if running
216
+ sleep 0.01
217
+ end
218
+ # p from_client.get
219
+ # p from_client.get {|s| s.split(",").map {|v| v.to_f}}
220
+ # p from_client.get {|s| s.unpack("N4")}
221
+
222
+ else # client
223
+ to_server = SimpleIPC::IPC.new :port => 5000, :kind => :udp
224
+ to_server.send([1,2,3, "test"])
225
+ to_server.send({:a => "test", :b => "prova"})
226
+ to_server.send("stop")
227
+
228
+ # to_server.send([1,2,3,4]) {|o| o * ","}
229
+ # to_server.send(ary) {|o| o.pack("N#{ary.size}")}
230
+ to_server.close
231
+ end
232
+ end
233
+
234
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # test
3
+ #
4
+ # Created by Paolo Bosetti on 2011-01-18.
5
+ # Copyright (c) 2011 University of Trento. All rights reserved.
6
+ #
7
+
8
+ require "./lib/simple_ipc"
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_ipc
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 1
8
+ version: "1.1"
9
+ platform: ruby
10
+ authors:
11
+ - Paolo Bosetti
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2011-01-19 00:00:00 +01:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description: Simple Inter-Process Communication library
21
+ email: paolo.bosetti@me.com
22
+ executables: []
23
+
24
+ extensions: []
25
+
26
+ extra_rdoc_files: []
27
+
28
+ files:
29
+ - README.md
30
+ - lib/simple_ipc.rb
31
+ - test/test.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/pbosetti/simpleipc
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --inline-source
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ requirements: []
59
+
60
+ rubyforge_project: simple_ipc
61
+ rubygems_version: 1.3.7
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Simple Inter-Process Communication library
65
+ test_files: []
66
+