Class: Ionian::Socket

Inherits:
Object
  • Object
show all
Defined in:
lib/ionian/socket.rb

Overview

A convenient wrapper for TCP, UDP, and Unix client sockets.

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Socket) initialize(existing_socket = nil, **kwargs)

Creates a new socket or wraps an existing socket.

Args:

host:       IP or hostname to connect to. Can contain the port in the format "host:port".
port:       Connection's port number. Default is 23. Unused by :unix protocol.
protocol:   Type of socket to create. :tcp, :udp, :unix. Default is :tcp.
            :udp will be automatically selected for addresses in the multicast range.
persistent: The socket remains open after data is sent if this is true.
            The socket closes after data is sent and a packet is received
            if this is false. Default is true.
bind_port:  Local UDP port to bind to for receiving data, if different than
            the remote port being connected to.
reuse_addr: Set true to enable the SO_REUSEADDR flag. Allows local address reuse.
no_delay:   Set true to enable the TCP_NODELAY flag. Disables Nagle algorithm.
cork:       Set true to enable the TCP_CORK flag. Buffers multiple writes
            into one segment.
expression: Overrides the #read_match regular expression for received data.


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ionian/socket.rb', line 40

def initialize existing_socket = nil, **kwargs
  @socket = existing_socket
  
  @ionian_listeners = []
  
  @expression = kwargs.fetch :expression, nil
  
  if existing_socket
    # Convert existing socket.
    @socket.extend Ionian::Extension::IO
    @socket.extend Ionian::Extension::Socket
    
    if existing_socket.is_a? UNIXSocket
      @host = existing_socket.path
      @port = nil
    else
      @host = existing_socket.remote_address.ip_address if existing_socket
      @port = existing_socket.remote_address.ip_port if existing_socket
    end
  
    if @socket.is_a? TCPSocket
      @protocol = :tcp
    elsif @socket.is_a? UDPSocket
      @protocol = :udp
    elsif @socket.is_a? UNIXSocket
      @protocol = :unix
    end
    
    @persistent     = true # Existing sockets are always persistent.
    
    @socket.expression = @expression if @expression
    
    initialize_socket_methods
    
  else
    # Initialize new socket.
    
    # Parse host out of "host:port" if specified.
    host_port_ary   = kwargs.fetch(:host).to_s.split ':'
    
    @host           = host_port_ary[0]
    @port           = kwargs.fetch :port, host_port_ary[1].to_i || 23
    @bind_port      = kwargs.fetch :bind_port,  @port
    
    # Automatically select UDP for the multicast range. Otherwise default to TCP.
    default_protocol = :tcp
    default_protocol = :udp  if Ionian::Extension::Socket.multicast? @host
    default_protocol = :unix if @host.start_with? '/'
    
    @protocol       = kwargs.fetch :protocol,   default_protocol
    @persistent     = kwargs.fetch :persistent, true
    @persistent     = true if @protocol == :udp
    
    @reuse_addr     = kwargs.fetch :reuse_addr, false
    @no_delay       = kwargs.fetch :no_delay,   false
    @cork           = kwargs.fetch :cork,       false
  
    
    create_socket if @persistent
  end
end

Instance Attribute Details

- (Object) bind_port (readonly)

Local port number.



15
16
17
# File 'lib/ionian/socket.rb', line 15

def bind_port
  @bind_port
end

- (Object) host (readonly)

IP address or URL of server.



9
10
11
# File 'lib/ionian/socket.rb', line 9

def host
  @host
end

- (Object) port (readonly)

Remote port number.



12
13
14
# File 'lib/ionian/socket.rb', line 12

def port
  @port
end

- (Object) protocol (readonly) Also known as: protocol?

Returns a symbol of the type of protocol this socket uses: :tcp, :udp, :unix



19
20
21
# File 'lib/ionian/socket.rb', line 19

def protocol
  @protocol
end

Instance Method Details

- (Boolean) closed?

Returns true if the socket is closed.

Returns:

  • (Boolean)


170
171
172
173
# File 'lib/ionian/socket.rb', line 170

def closed?
  return true unless @socket
  @socket.closed?
end

- (Object) cmd(string, **kwargs, &block)

Send a command (data) to the socket. Returns an array of received matches. Block yields received match. See Ionian::Extension::IO#read_match.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ionian/socket.rb', line 122

def cmd string, **kwargs, &block
  create_socket unless @persistent
  
  if @protocol == :udp
    @socket.send string, 0
  else
    @socket.write string
  end
  
  @socket.flush
  
  matches = @socket.read_match(kwargs) { |match| yield match if block_given? }
  @socket.close unless @persistent
  
  matches
end

- (Object) expression

Returns the regular expression used to match incoming data.



103
104
105
# File 'lib/ionian/socket.rb', line 103

def expression
  @expression || @socket.expression
end

- (Object) expression=(exp)

Set the regular expression used to match incoming data.



108
109
110
111
# File 'lib/ionian/socket.rb', line 108

def expression= exp
  @expression = exp
  @socket.expression = exp if @socket
end

- (Object) flush

Flushes buffered data to the operating system. This method has no effect on non-persistent sockets.



177
178
179
# File 'lib/ionian/socket.rb', line 177

def flush
  @socket.flush if @persistent
end

- (Boolean) has_data?(**kwargs)

Returns true if there is data in the receive buffer. Args:

Timeout: Number of seconds to wait for data until
  giving up. Set to nil for blocking.

Returns:

  • (Boolean)


164
165
166
167
# File 'lib/ionian/socket.rb', line 164

def has_data? **kwargs
  return false unless @socket
  @socket.has_data? kwargs
end

- (Boolean) persistent?

Returns true if the socket remains open after writing data.

Returns:

  • (Boolean)


114
115
116
# File 'lib/ionian/socket.rb', line 114

def persistent?
  @persistent == false || @persistent == nil ? false : true
end

- (Object) puts(*string)

Writes the given string(s) to the socket and appends a newline character to any string not already ending with one.



183
184
185
# File 'lib/ionian/socket.rb', line 183

def puts *string
  self.write string.map{ |s| s.chomp }.join("\n") + "\n"
end

- (Object) register_observer(&block) Also known as: on_match

Register a block to be called when #run_match receives matched data. Method callbacks can be registered with &object.method(:method). Returns a reference to the given block. block = ionian_socket.register_observer { … }



143
144
145
146
147
# File 'lib/ionian/socket.rb', line 143

def register_observer &block
  @ionian_listeners << block unless @ionian_listeners.include? block
  @socket.register_observer &block if @socket
  block
end

- (Object) unregister_observer(&block)

Unregister a block from being called when matched data is received.



152
153
154
155
156
# File 'lib/ionian/socket.rb', line 152

def unregister_observer &block
  @ionian_listeners.delete_if { |o| o == block }
  @socket.unregister_observer &block if @socket
  block
end

- (Object) write(string) Also known as: <<

Writes the given string to the socket. Returns the number of bytes written.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/ionian/socket.rb', line 189

def write string
  create_socket unless @persistent
  
  num_bytes = 0
  
  if @protocol == :udp
    num_bytes = @socket.send string, 0
  else
    num_bytes = @socket.write string
  end
  
  unless @persistent
    # Read in data to prevent RST packets.
    has_data = ::IO.select [@socket], nil, nil, 0
    @socket.readpartial 0xFFFF if has_data
    
    @socket.close
  end
  
  num_bytes
end