easy_sockets 0.1.0 → 1.0.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.
- checksums.yaml +4 -4
- data/{CHANGELOG.rb → CHANGELOG.md} +3 -1
- data/README.md +78 -2
- data/examples/tcp_socket.rb +1 -1
- data/examples/udp_socket.rb +26 -0
- data/lib/easy_sockets.rb +1 -0
- data/lib/easy_sockets/tcp/tcp_socket.rb +1 -1
- data/lib/easy_sockets/udp/udp_server.rb +83 -0
- data/lib/easy_sockets/udp/udp_socket.rb +35 -0
- data/lib/easy_sockets/utils/server_utils.rb +19 -0
- data/lib/easy_sockets/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f80b06dbbb87b666cb3b6664d405c95e1a1fc27f
|
4
|
+
data.tar.gz: 4494590df3d194153ccbe2ecdd530d49fac19df7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01bc5222921c85853927282f57c97de241dbb4ff8d7d9c25627974b3f55422030cb88c9ed9d377c3875dca2fbf08aabb7de2ead1a36339e63f46fccbc6961ac9
|
7
|
+
data.tar.gz: 19fe1923e0063a4f36faa055ceada93a089d322f2a3dc0aac06cd5f344aa03dc28fac7b91f067acbaae331833ae3484aa0b4c0f8ade9bf3cbb9850e5f3d2d67d
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
|
21
21
|
## Description
|
22
22
|
|
23
|
-
Over and over I see developers struggling to implement basic sockets with
|
23
|
+
Over and over I see developers struggling to implement basic sockets with features available on ruby socket stdlib.
|
24
24
|
|
25
25
|
easy_sockets, takes care of basic details that usually are overlooked by developers when implementing TCP/Unix sockets from scratch.
|
26
26
|
|
@@ -191,7 +191,7 @@ Press `Ctrl+c` on the client and server terminal windows to terminate both.
|
|
191
191
|
|
192
192
|
Open up a terminal window and type the following to start a Unix server:
|
193
193
|
```bash
|
194
|
-
nc -
|
194
|
+
nc -Ucl /tmp/test_socket
|
195
195
|
```
|
196
196
|
|
197
197
|
On another terminal window, run the following [code](https://github.com/marcosortiz/easy_sockets/blob/master/examples/unix_socket.rb) to start the client:
|
@@ -263,6 +263,82 @@ Please write the message you want to send and hit ENTER, or type Ctrl+c to quit:
|
|
263
263
|
|
264
264
|
Press `Ctrl+c` on the client and server terminal windows to terminate both. Also, type `rm -rf /tmp/test_socket` to remove the socket file.
|
265
265
|
|
266
|
+
### UDP Sockets
|
267
|
+
|
268
|
+
Open up a terminal window and type the following to start a TCP server:
|
269
|
+
```bash
|
270
|
+
nc -ukcl 2500
|
271
|
+
```
|
272
|
+
|
273
|
+
On another terminal window, run the following [code](https://github.com/marcosortiz/easy_sockets/blob/master/examples/udp_socket.rb) to start the client:
|
274
|
+
```ruby
|
275
|
+
require 'easy_sockets'
|
276
|
+
|
277
|
+
host = ARGV[0] || '127.0.0.1'
|
278
|
+
|
279
|
+
port = ARGV[1].to_i
|
280
|
+
port = 2500 if port <= 0
|
281
|
+
|
282
|
+
opts = {
|
283
|
+
host: host,
|
284
|
+
port: port,
|
285
|
+
timeout: 300,
|
286
|
+
separator: "\r\n",
|
287
|
+
logger: Logger.new(STDOUT),
|
288
|
+
}
|
289
|
+
s = EasySockets::UdpSocket.new(opts)
|
290
|
+
[:INT, :QUIT, :TERM].each do |signal|
|
291
|
+
Signal.trap(signal) do
|
292
|
+
exit
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
loop do
|
297
|
+
puts "Please write the message you want to send and hit ENTER, or type Ctrl+c to quit:"
|
298
|
+
msg = gets.chomp
|
299
|
+
s.send_msg(msg)
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
303
|
+
Then typing `sample_request` in the client terminal, you should see:
|
304
|
+
```
|
305
|
+
$ bundle exec ruby examples/udp_socket.rb
|
306
|
+
Please write the message you want to send and hit ENTER, or type Ctrl+c to quit:
|
307
|
+
sample_request
|
308
|
+
D, [2016-07-08T10:45:17.935787 #83697] DEBUG -- : Successfully connected to udp://127.0.0.1:2500.
|
309
|
+
D, [2016-07-08T10:45:17.935893 #83697] DEBUG -- : Sending "sample_request\r\n"
|
310
|
+
|
311
|
+
```
|
312
|
+
|
313
|
+
And the server terminal window should display:
|
314
|
+
```
|
315
|
+
$ nc -ukcl 2500
|
316
|
+
sample_request
|
317
|
+
|
318
|
+
```
|
319
|
+
|
320
|
+
Then type `sample_response` on the server terminal window, and you should see:
|
321
|
+
```
|
322
|
+
$ nc -ukcl 2500
|
323
|
+
sample_request
|
324
|
+
sample_response
|
325
|
+
|
326
|
+
```
|
327
|
+
|
328
|
+
And the client window should show:
|
329
|
+
```
|
330
|
+
$ bundle exec ruby examples/udp_socket.rb
|
331
|
+
Please write the message you want to send and hit ENTER, or type Ctrl+c to quit:
|
332
|
+
sample_request
|
333
|
+
D, [2016-07-08T10:45:17.935787 #83697] DEBUG -- : Successfully connected to udp://127.0.0.1:2500.
|
334
|
+
D, [2016-07-08T10:45:17.935893 #83697] DEBUG -- : Sending "sample_request\r\n"
|
335
|
+
D, [2016-07-08T10:45:22.086731 #83697] DEBUG -- : Got "sample_response\r\n"
|
336
|
+
Please write the message you want to send and hit ENTER, or type Ctrl+c to quit:
|
337
|
+
|
338
|
+
```
|
339
|
+
|
340
|
+
Press `Ctrl+c` on the client and server terminal windows to terminate both.
|
341
|
+
|
266
342
|
## Development
|
267
343
|
|
268
344
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/examples/tcp_socket.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'easy_sockets'
|
2
|
+
|
3
|
+
host = ARGV[0] || '127.0.0.1'
|
4
|
+
|
5
|
+
port = ARGV[1].to_i
|
6
|
+
port = 2500 if port <= 0
|
7
|
+
|
8
|
+
opts = {
|
9
|
+
host: host,
|
10
|
+
port: port,
|
11
|
+
timeout: 300,
|
12
|
+
separator: "\r\n",
|
13
|
+
logger: Logger.new(STDOUT),
|
14
|
+
}
|
15
|
+
s = EasySockets::UdpSocket.new(opts)
|
16
|
+
[:INT, :QUIT, :TERM].each do |signal|
|
17
|
+
Signal.trap(signal) do
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
loop do
|
23
|
+
puts "Please write the message you want to send and hit ENTER, or type Ctrl+c to quit:"
|
24
|
+
msg = gets.chomp
|
25
|
+
s.send_msg(msg)
|
26
|
+
end
|
data/lib/easy_sockets.rb
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'socket'
|
3
|
+
require 'easy_sockets/constants'
|
4
|
+
require 'easy_sockets/utils/server_utils'
|
5
|
+
|
6
|
+
module EasySockets
|
7
|
+
#
|
8
|
+
# This class was created for testing purposes only. It should not be used
|
9
|
+
# in production.
|
10
|
+
#
|
11
|
+
class UdpServer
|
12
|
+
include EasySockets::ServerUtils
|
13
|
+
|
14
|
+
attr_reader :connections
|
15
|
+
|
16
|
+
DEFAULT_TIMEOUT = 0.5 # seconds
|
17
|
+
|
18
|
+
def initialize(opts={})
|
19
|
+
set_opts(opts)
|
20
|
+
@started = false
|
21
|
+
@stop_requested = false
|
22
|
+
@connections = []
|
23
|
+
register_shutdown_signals
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
return if @started
|
28
|
+
@started = true
|
29
|
+
@socket = UDPSocket.new
|
30
|
+
@socket.bind('127.0.0.1', @port)
|
31
|
+
@logger.info "Listening on udp://127.0.0.1:#{@port}"
|
32
|
+
loop do
|
33
|
+
shutdown if @stop_requested
|
34
|
+
# connection = accept_non_block(@socket)
|
35
|
+
# @connections << connection
|
36
|
+
# handle(connection)
|
37
|
+
handle(@socket)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop
|
42
|
+
return unless @started
|
43
|
+
@stop_requested = true
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def set_opts(opts)
|
49
|
+
@port = opts[:port].to_i
|
50
|
+
@port = DEFAULT_PORT if @port <= 0
|
51
|
+
|
52
|
+
@logger = opts[:logger] || Logger.new(STDOUT)
|
53
|
+
|
54
|
+
@separator = opts[:separator]
|
55
|
+
@separator ||= EasySockets::CRLF
|
56
|
+
|
57
|
+
@sleep_time = opts[:sleep_time].to_f
|
58
|
+
@sleep_time = 0.0001 if @sleep_time <= 0.0
|
59
|
+
|
60
|
+
@timeout = opts[:timeout].to_f
|
61
|
+
@timeout = DEFAULT_TIMEOUT if @timeout <= 0.0
|
62
|
+
end
|
63
|
+
|
64
|
+
def handle(connection)
|
65
|
+
loop do
|
66
|
+
shutdown if @stop_requested
|
67
|
+
begin
|
68
|
+
msg, addr = udp_read_non_block(connection)
|
69
|
+
sleep @sleep_time
|
70
|
+
unless msg.nil?
|
71
|
+
connection.send(msg, 0, addr[3], addr[1])
|
72
|
+
@logger.info "Sent: #{msg.inspect}"
|
73
|
+
end
|
74
|
+
rescue EOFError, Errno::ECONNRESET
|
75
|
+
connection.close
|
76
|
+
@logger.info 'Client disconnected.'
|
77
|
+
break
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'easy_sockets/basic_socket'
|
2
|
+
|
3
|
+
module EasySockets
|
4
|
+
#
|
5
|
+
# @author Marcos Ortiz
|
6
|
+
# Subclass of {EasySockets::BasicSocket} that implement a UDP socket.
|
7
|
+
#
|
8
|
+
class UdpSocket < EasySockets::BasicSocket
|
9
|
+
|
10
|
+
#
|
11
|
+
# @param [Hash] opts the options to create a socket with.
|
12
|
+
# @option opts [Integer] :port (2000) The udp port the server is running on.
|
13
|
+
# @option opts [String] :host ('127.0.0.1') The hostname or IP address the server is running on.
|
14
|
+
#
|
15
|
+
# It also accepts all options that {EasySockets::BasicSocket#initialize} accepts
|
16
|
+
def initialize(opts={})
|
17
|
+
super(opts)
|
18
|
+
|
19
|
+
@port = opts[:port].to_i
|
20
|
+
@port = DEFAULT_PORT if @port <= 0
|
21
|
+
@host = opts[:host] || DEFAULT_HOST
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def on_connect
|
27
|
+
@socket = UDPSocket.new
|
28
|
+
@socket.connect(@host, @port)
|
29
|
+
log(:debug, "Successfully connected to udp://#{@host}:#{@port}.")
|
30
|
+
rescue Exception => e
|
31
|
+
@socket.close if @socket && !@socket.closed?
|
32
|
+
raise e
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -37,6 +37,25 @@ module EasySockets
|
|
37
37
|
msg
|
38
38
|
end
|
39
39
|
|
40
|
+
def udp_read_non_block(connection)
|
41
|
+
total_msg = ''
|
42
|
+
addr = nil
|
43
|
+
begin
|
44
|
+
msg, addr = connection.recvfrom_nonblock(CHUNK_SIZE)
|
45
|
+
total_msg << msg
|
46
|
+
while !total_msg.end_with?(@separator) do
|
47
|
+
msg, addr = connection.recvfrom_nonblock(EasySockets::CHUNK_SIZE)
|
48
|
+
total_msg << msg
|
49
|
+
end
|
50
|
+
@logger.info "Got: #{total_msg.inspect}" unless total_msg.nil? || total_msg.empty?
|
51
|
+
total_msg.empty? ? nil : [total_msg, addr]
|
52
|
+
rescue IO::WaitReadable
|
53
|
+
if IO.select([connection], nil, nil, @timeout)
|
54
|
+
retry
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
40
59
|
def write_non_block(connection, msg)
|
41
60
|
return 0 unless msg && msg.is_a?(String)
|
42
61
|
total_bytes = 0
|
data/lib/easy_sockets/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easy_sockets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcos Ortiz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,7 @@ files:
|
|
66
66
|
- ".rspec"
|
67
67
|
- ".travis.yml"
|
68
68
|
- ".yardopts"
|
69
|
-
- CHANGELOG.
|
69
|
+
- CHANGELOG.md
|
70
70
|
- Gemfile
|
71
71
|
- LICENSE.txt
|
72
72
|
- README.md
|
@@ -75,12 +75,15 @@ files:
|
|
75
75
|
- bin/setup
|
76
76
|
- easy_sockets.gemspec
|
77
77
|
- examples/tcp_socket.rb
|
78
|
+
- examples/udp_socket.rb
|
78
79
|
- examples/unix_socket.rb
|
79
80
|
- lib/easy_sockets.rb
|
80
81
|
- lib/easy_sockets/basic_socket.rb
|
81
82
|
- lib/easy_sockets/constants.rb
|
82
83
|
- lib/easy_sockets/tcp/tcp_server.rb
|
83
84
|
- lib/easy_sockets/tcp/tcp_socket.rb
|
85
|
+
- lib/easy_sockets/udp/udp_server.rb
|
86
|
+
- lib/easy_sockets/udp/udp_socket.rb
|
84
87
|
- lib/easy_sockets/unix/unix_server.rb
|
85
88
|
- lib/easy_sockets/unix/unix_socket.rb
|
86
89
|
- lib/easy_sockets/utils.rb
|
@@ -111,3 +114,4 @@ signing_key:
|
|
111
114
|
specification_version: 4
|
112
115
|
summary: Wrapper around ruby socket stdlib to make developer's life easier'.
|
113
116
|
test_files: []
|
117
|
+
has_rdoc:
|