views:

1346

answers:

3

I need a quick way to find out if a given port is open with Ruby. I currently am fiddling around with this:

require 'socket'

def is_port_open?(ip, port)
  begin
    TCPSocket.new(ip, port)
  rescue Errno::ECONNREFUSED
    return false
  end
  return true
end

It works great if the port is open, but the downside of this is that occasionally it will just sit and wait for 10-20 seconds and then eventually time out, throwing a ETIMEOUT exception (if the port is closed). My question is thus:

Can this code be amended to only wait for a second (and return false if we get nothing back by then) or is there a better way to check if a given port is open on a given host?

Edit: Calling bash code is acceptable also as long as it works cross-platform (e.g., Mac OS X, *nix, and Cygwin), although I do prefer Ruby code.

+2  A: 

Something like the following might work:

require 'socket'
require 'timeout'

def is_port_open?(ip, port)
  begin
    Timeout::timeout(1) do
      begin
        s = TCPSocket.new(ip, port)
        s.close
        return true
      rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
        return false
      end
    end
  rescue Timeout::Error
  end

  return false
end
joast
Works like a charm! Thanks!
Chris Bunch
A: 

Just for completeness, the Bash would be something like this:

$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something

-w 1 specifies a timeout of 1 second, and -q 0 says that, when connected, close the connection as soon as stdin gives EOF (which /dev/null will do straight away).

Bash also has its own built-in TCP/UDP services, but they are a compile-time option and I don't have a Bash compiled with them :P

Porges
They're pretty simple: just pretend /dev/{tcp}/HOST/PORT are files :)
ephemient
A: 

I was looking for this same solution. I have Ruby 1.9.1 installed on Windows and, when I try your example is_port_open test, it does not work. The socket call still takes around 20 seconds to timeout no matter what value I set for the timeout. Any ideas on why?

Mark
I don't know what what causes it to work incorrectly with 1.9.1 on Windows. It does work with 1.8.7 on Windows.
joast