0

I'm trying to check if a given host is up, running, and listening to a specific port, and to handle any errors correctly.

I found a a number of references of Ruby socket programming but none of them seems to able to handle "socket time-out" efficiently. I tried IO.select, which takes four parameters, of which, the last one is the timeout value:

IO.select([TCPSocket.new('example.com', 22)], [nil], [nil], 4)

The problem is, it gets stuck, especially if the port number is wrong or the server is not listening on to it. So, finally I ended up with this, which I didn't like that much but doing the job:

require 'socket'
require 'timeout'
dns = "example.com"

begin
    Timeout::timeout(3) { TCPSocket.new(dns, 22) }
    puts "Responded!!"
    # do some stuff here...
rescue SocketError
    puts "No connection!!"
    # do some more stuff here...
rescue Timeout::Error
    puts "No connection, timed out!!"
    # do some other stuff here...
end

Is there a better way doing this?

MacUsers
  • 2,091
  • 3
  • 35
  • 56
  • 1
    My question is, if you're trying to check a host you're supposed to be testing, why don't you know what port it's listening to? I'd know the port before I even begin coding. – the Tin Man Jul 30 '13 at 23:52
  • @theTinMan: First off, You know or not, there shouldn't be any 'unprotected action' in you script. I'm not a programmer but that's the very first thing I learned from a number of much experienced coders. If you haven't look at this part of the world, you better start looking. There are some other possibilities as well: What if the script is running through a automatically generated file with host/port information in it and that file was sick. What if the port number is right but the server is not listening to it? Secondly, you've wasted time on which is not the answer to my question at all. – MacUsers Jul 31 '13 at 11:33
  • I didn't waste time asking a question in a comment. One of the purposes of comments in Stack Overflow, is to determine whether you've thought of certain things: "Use comments to ask for more information or suggest improvements." I wanted to make sure you'd dealt with that, because, all too often here, people miss the basics. I'm very aware of "defensive programming" and using exception handling to react to unexpected events; It's something that comes with years of experience. There are some very experienced Ruby programmers here. – the Tin Man Jul 31 '13 at 13:54
  • possible duplicate of [Set socket timeout in Ruby via SO\_RCVTIMEO socket option](http://stackoverflow.com/questions/9853516/set-socket-timeout-in-ruby-via-so-rcvtimeo-socket-option) – the Tin Man Jul 31 '13 at 14:03
  • @theTinMan: I never meant to offend you at all; my apology if I sounded like that. I don't consider myself an "experienced programmer" at all but I've seen people to "assume" a lot of thing as they go coding, even a few experienced once. Sorry about that. Cheers!! – MacUsers Aug 20 '13 at 14:20

2 Answers2

1

The best test for availability of any resource is to try to use it. Adding extra code to try to predict ahead of time whether the use will work is bound to fail:

  1. You test the wrong thing and get a different answer.
  2. You test the right thing but at the wrong time, and the answer changes between the test and the use, and your application performs double the work for nothing, and you write redundant code.
  3. The code you have to write to handle the test failure is identical to the code you should write to handle the use-failure. Why write that twice?
user207421
  • 305,947
  • 44
  • 307
  • 483
0

We make extensive use of Net::SSH in one of our systems, and ran into timeout issues.

Probably the biggest fix was to implement use of the select method, to set a low-level timeout, and not try to use the Timeout class, which is thread based.

"How do I set the socket timeout in Ruby?" and "Set socket timeout in Ruby via SO_RCVTIMEO socket option" have code to investigate for that. Also, one of those links to "Socket Timeouts in Ruby" which has useful code, however be aware that it was written for Ruby 1.8.6.

The version of Ruby can make a difference too. Pre-1.9 the threading wasn't capable of stopping a blocking IP session so the code would hang until the socket timed out, then the Timeout would fire. Both the above questions go over that.

Community
  • 1
  • 1
the Tin Man
  • 158,662
  • 42
  • 215
  • 303