Forum: Ruby Detect TCPSocket interruptions/disappearance

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
92ce537e2c732b0300d9ea97f6bf3fe3?d=identicon&s=25 Andrew Edwards (Guest)
on 2009-05-19 12:31
(Received via mailing list)
Hi,

I am putting together a background daemon as part of a Rails app to
handle monitoring of our phone system. The phone system exposes an TCP
socket on which it delivers lines of text in real-time corresponding
to events (new call etc).

I have put together a skeleton process to monitor this, shown below.
However I am not sure how to reliably detect when the phone system
goes away, say it is rebooted or similar.

In such a case the code simply hangs on the gets request within the
loop and never returns.

When the phone system is visible again the original connection is
either lost or timed-out, hence nothing is submitted for the daemon to
receive. Ideally I need to detect this and re-open a connection via
the daemon.

Is the gets method even the best method for this scenario?

I had considered having a separate thread monitoring the visibility of
the server and if it disappears signal to cycle the connection.
Although I'm sure there may be a better way...

Any thoughts much appreciated, Andrew.


begin

  TCPSocket::open("192.168.10.130", 4005) do |socket|

    $running = true

    Signal.trap("TERM") do
      $running = false
      socket.close
    end

    socket.puts "LOGIN,\n"
    if socket.gets == "LOGINOK\n"
      ActiveRecord::Base.logger.info "Successful Login, Start Monitor"
      while($running) do
        routing_message = socket.gets
        ActiveRecord::Base.logger.info DateTime.now.to_s + " " +
routing_message
      end
      ActiveRecord::Base.logger.info "Stop Monitor"
    else
      ActiveRecord::Base.logger.info "Failed Login"
    end

  end

rescue *ErrorsOnSocket => err
  ActiveRecord::Base.logger.info "Socket Error, Retrying..."
  sleep 15
  retry
end
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-05-19 15:46
Andrew Edwards wrote:
> I have put together a skeleton process to monitor this, shown below.
> However I am not sure how to reliably detect when the phone system
> goes away, say it is rebooted or similar.

Try setting SO_KEEPALIVE on your socket.

It's easier if you can send a periodic message to the far side and check
you get a response within a second or two. However if you can't do that
- i.e. you have to be an entirely passive listener - then SO_KEEPALIVE
sends periodic probes at the TCP layer. It may take a few minutes to
detect that the connection has gone though.
Bec38d63650c8912b6ba9b557fb953b9?d=identicon&s=25 Roger Pack (rogerdpack)
on 2009-05-20 14:42
> In such a case the code simply hangs on the gets request within the
> loop and never returns.

Odd. If the socket closes then gets should return nil

So in this case the only way you know it closed is that...it goes away
without notifying you?
If that's the case then some type of periodic liveness ping is the only
way, I think (as Brian noted).
-=r
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-05-20 15:04
Roger Pack wrote:
>> In such a case the code simply hangs on the gets request within the
>> loop and never returns.
>
> Odd. If the socket closes then gets should return nil

Only if the far-end closes the socket normally. If the machine is just
powered off or hard-resets, obviously no packet will be sent. And when
it comes back up, it won't know that it used to have an open connection.

If you send data *to* it, it will respond with a RST. But this won't
happen if you're just passively listening.
This topic is locked and can not be replied to.