class Ionian::Socket

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

Attributes

protocol[R]

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

protocol?[R]

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

Public Class Methods

new(existing_socket = nil, **kwargs) click to toggle source

Creates a new socket or wraps an existing socket.

Args:

host:       IP or hostname to connect to.
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.
# File lib/ionian/socket.rb, line 25
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.
    
    # TODO: Should be able to parse the port out of host.
    #       :port should override this parsed value.
    
    @host           = kwargs.fetch :host
    @port           = kwargs.fetch :port,       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

Public Instance Methods

<<(string)
Alias for: write
closed?() click to toggle source

Returns true if the socket is closed.

# File lib/ionian/socket.rb, line 159
def closed?
  return true unless @socket
  @socket.closed?
end
cmd(string, **kwargs) { |match| ... } click to toggle source

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

# File lib/ionian/socket.rb, line 111
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
expression() click to toggle source

Returns the regular expression used to match incoming data.

# File lib/ionian/socket.rb, line 92
def expression
  @expression || @socket.expression
end
expression=(exp) click to toggle source

Set the regular expression used to match incoming data.

# File lib/ionian/socket.rb, line 97
def expression=(exp)
  @expression = exp
  @socket.expression = exp if @socket
end
flush() click to toggle source

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

# File lib/ionian/socket.rb, line 166
def flush
  @socket.flush if @persistent
end
has_data?(**kwargs) click to toggle source

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.
# File lib/ionian/socket.rb, line 153
def has_data?(**kwargs)
  return false unless @socket
  @socket.has_data? kwargs
end
on_match(&block)
Alias for: register_observer
persistent?() click to toggle source

Returns true if the socket remains open after writing data.

# File lib/ionian/socket.rb, line 103
def persistent?
  @persistent == false || @persistent == nil ? false : true
end
puts(*string) click to toggle source

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

# File lib/ionian/socket.rb, line 172
def puts(*string)
  self.write string.map{|s| s.chomp}.join("\n") + "\n"
end
register_observer(&block) click to toggle source

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 {…}

# File lib/ionian/socket.rb, line 132
def register_observer &block
  @ionian_listeners << block unless @ionian_listeners.include? block
  @socket.register_observer &block if @socket
  block
end
Also aliased as: on_match
unregister_observer(&block) click to toggle source

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

# File lib/ionian/socket.rb, line 141
def unregister_observer(&block)
  @ionian_listeners.delete_if {|o| o == block}
  @socket.unregister_observer &block if @socket
  block
end
write(string) click to toggle source

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

# File lib/ionian/socket.rb, line 178
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
Also aliased as: <<