lib/ionian/socket.rb in ionian-0.6.6 vs lib/ionian/socket.rb in ionian-0.6.7

- old
+ new

@@ -34,10 +34,12 @@ # 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. + # linger: Set true to enable the SO_LINGER flag. When #close is called, + # waits for the send buffer to empty before closing the socket. # expression: Overrides the #read_match regular expression for received data. def initialize existing_socket = nil, **kwargs @socket = existing_socket @ionian_listeners = [] @@ -89,12 +91,18 @@ @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 + @no_delay = kwargs.fetch :no_delay, @persistent ? false : true + + # Default to false for persistent sockets, true for + # nonpersistent sockets. When nonpersistent, the socket + # should remain open to send data in the buffer after + # close is called (typically right after write). + @linger = kwargs.fetch :linger, @persistent ? false : true create_socket if @persistent end end @@ -120,16 +128,11 @@ # Block yields received match. # See Ionian::Extension::IO#read_match. def cmd string, **kwargs, &block create_socket unless @persistent - if @protocol == :udp - @socket.send string, 0 - else - @socket.write string - end - + write string @socket.flush matches = @socket.read_match(kwargs) { |match| yield match if block_given? } @socket.close unless @persistent @@ -196,14 +199,20 @@ else num_bytes = @socket.write string end unless @persistent + @socket.flush + # Read in data to prevent RST packets. - has_data = ::IO.select [@socket], nil, nil, 0 - @socket.readpartial 0xFFFF if has_data + # TODO: Shutdown read stream instead? + @socket.read_all nonblocking: true + # TODO: Sleep added so that data can be read on the receiving + # end. Can this be changed to shutdown write? + # Why isn't so_linger taking care of this? + sleep 0.01 @socket.close end num_bytes end @@ -219,14 +228,14 @@ case @protocol when :tcp @socket = ::TCPSocket.new @host, @port @socket.extend Ionian::Extension::Socket - @socket.expression = @expression if @expression - @socket.no_delay = true if @no_delay - @socket.cork = true if @cork + @socket.no_delay = @no_delay + @socket.cork = @cork + when :udp @socket = ::UDPSocket.new @socket.extend Ionian::Extension::Socket @socket.reuse_addr = true if @@ -238,13 +247,13 @@ @socket.ip_add_membership if Ionian::Extension::Socket.multicast? @host when :unix @socket = ::UNIXSocket.new @host @socket.extend Ionian::Extension::Socket + end - # TODO: Implement SO_LINGER flag for non-persistent sockets; - # especially send-and-forget. + @socket.linger = @linger @socket.expression = @expression if @expression # Register listeners. @ionian_listeners.each { |proc| @socket.on_match &proc } \ No newline at end of file