Check if Internet Connection Exists with Ruby?
Asked Answered
D

7

19

Just asked how to check if an internet connection exists using javascript and got some great answers. What's the easiest way to do this in Ruby? In trying to make generated html markup code as clean as possible, I'd like to conditionally render the script tag for javascript files depending on whether or not an internet condition. Something like (this is HAML):

- if internet_connection?
    %script{:src => "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", :type => "text/javascript"}
- else
    %script{:src => "/shared/javascripts/jquery/jquery.js", :type => "text/javascript"}
Dhyana answered 5/3, 2010 at 7:30 Comment(3)
possible duplicate of Checking for internet connectionIfill
@CiroSantilli the question you indicated is older, but this is better worded and has substantially better answers...Unlimber
@BradWerth whichever one we dupe is fine by me ;) I think the other is as good since the context here didn't add much to my underestanding: I read the one liner from the other question and understood the same question.Ifill
B
7

You can use the Ping class in Ruby <=1.9:

require 'resolv-replace'
require 'ping'

def internet_connection?
  Ping.pingecho "google.com", 1, 80
end

The method returns true or false and doesn't raise exceptions.

Burnard answered 5/3, 2010 at 9:53 Comment(3)
Why the need to require 'resolv-replace'? Also, 'ping' has been dropped from the 1.9 standard lib. I came up with a simple enough work around here...but if there's a better way to do this for 1.9, let me know.Faustofaustus
This is wrong. A firewall could be blocking ICMP, in which case this would return false. But the internet connection could be fine.Manly
Is this the most ideal way? I mean how does windows get to know if i have to sign in a wifi? Do they ping some servers? (It is completely off topic)Hobard
Z
22
require 'open-uri'

def internet_connection?
  begin
    true if open("http://www.google.com/")
  rescue
    false
  end
end

This is closer to what the OP is looking for. It works in Ruby 1.8 and 1.9. It's a bit cleaner too.

Zwart answered 29/11, 2011 at 21:15 Comment(3)
+1 I had a similar need and that was the best AND most concise solution.Pacification
The problem with this command is that it can block for a long time if the connection is messy and adding the :read_timeout is not always reliable: open("http://www.google.com", { read_timeout: 5 } ) can block for way more than 5 seconds.Scarface
Right now, with my messy internet connection: puts Benchmark.measure { open("google.com", { read_timeout: 5 } ) } outputs 0.010000 0.000000 0.010000 ( 35.588267) => nilScarface
M
14

I love how everyone simply assume that googles servers are up. Creds to google.

If you want to know if you have internet without relying on google, then you could use DNS to see if you are able to get a connection.

You can use Ruby DNS Resolv to try to translate a url into an ip address. Works for Ruby version 1.8.6+

So:

#The awesome part: resolv is in the standard library

def has_internet?
  require "resolv"
  dns_resolver = Resolv::DNS.new()
  begin
    dns_resolver.getaddress("symbolics.com")#the first domain name ever. Will probably not be removed ever.
    return true
  rescue Resolv::ResolvError => e
    return false
  end
end

Hope this helps someone out :)

Martijn answered 3/4, 2014 at 12:11 Comment(8)
Or use icann.org. If that deprecates then DNS, and the internet, deprecates basically.Martijn
Getting an IP address doesn't mean that the IP is reachable.Manly
Good point about icann.org. I think another reason why people default to google is that it responds with the content faster. Though an HTTP HEAD request would even be faster and IMHO a better solution.Manly
@MarkThomas This is about checking if you have internet connection, not to check if any particular server is online.Martijn
Of course, you could just ping the dns root servers (a-m).root-servers.net. If all of those are down, we are in trouble.Martijn
Yes the root servers are a good idea, I just wouldn't use ICMP (ping) because that is sometimes blocked by corporate firewalls.Manly
This worked when none of the others did except for the open-uri method, which is slow. THANKSSkycap
Really an efficient way indeed.Hobard
B
7

You can use the Ping class in Ruby <=1.9:

require 'resolv-replace'
require 'ping'

def internet_connection?
  Ping.pingecho "google.com", 1, 80
end

The method returns true or false and doesn't raise exceptions.

Burnard answered 5/3, 2010 at 9:53 Comment(3)
Why the need to require 'resolv-replace'? Also, 'ping' has been dropped from the 1.9 standard lib. I came up with a simple enough work around here...but if there's a better way to do this for 1.9, let me know.Faustofaustus
This is wrong. A firewall could be blocking ICMP, in which case this would return false. But the internet connection could be fine.Manly
Is this the most ideal way? I mean how does windows get to know if i have to sign in a wifi? Do they ping some servers? (It is completely off topic)Hobard
H
5

Same basics as in Simone Carletti's answer but compatible with Ruby 2:

# gem install "net-ping"

require "net/ping"

def internet_connection?
  Net::Ping::External.new("8.8.8.8").ping?
end
Huzzah answered 9/7, 2015 at 13:32 Comment(2)
Same system I'm using in my pet tool interneeeeHuzzah
Yet another more efficient way than the accepted answer. Uses less bandwidth.Hobard
G
1
require 'open-uri'

page = "http://www.google.com/"
file_name = "output.txt"
output = File.open(file_name, "a")
begin
  web_page = open(page, :proxy_http_basic_authentication => ["http://your.company.proxy:80/", "your_user_name", "your_user_password"])  
  output.puts "#{Time.now}: connection established - OK !" if web_page
rescue Exception
  output.puts "#{Time.now}: Connection failed !"
  output.close
ensure
  output.close
end
Grueling answered 14/2, 2011 at 15:31 Comment(0)
S
0

I was trying to find a solution to a problem similar to yours and could not find any. Unfortunately the Ping.pingecho method doesn't work for me for some reason i don't know. I came up with a solution. The latest way to do it using httparty. I wanted this in a module and so did it this way and it works just fine

# gem install httparty
require "httparty"

module Main
  def Main.check_net
    begin
      a = HTTParty.get("https://www.google.com")
      if a.length() >= 100
        puts "online"
      end
    rescue SocketError
      puts "offline"
    end
  end
end

include Main
Main.check_net

A socket error to Google might not happen so this method will work

Six answered 8/7, 2021 at 17:57 Comment(0)
S
-1
def connected?
  !!Socket.getaddrinfo("google.com", "http")  
rescue SocketError => e
  e.message != 'getaddrinfo: nodename nor servname provided, or not known'
end

Since it uses a hostname the first thing it needs to do is DNS lookup, which causes the exception if there is no internet connection.

Sunrise answered 3/4, 2014 at 13:5 Comment(4)
Often DNS lookups are cached on a local server; this is no guarantee that the internet is reachable.Manly
Certainly a possibility.Sunrise
@MarkThomas The same argument can be used for the webpage itself. Often there are CDN servers and possibly caches on the routers themselves. And what about countries that block google.com? The only sure way to know is that you connect to a server you own that has some time-dependent data that it transfers to you that you can verify locally, and then, you only know you have access to that server. I know DNS is more common, but I'm just saying that there can be lots of other things going on as well.Martijn
While it's true that there are many potential hops, routers, caches, CDNs, etc. that make it nebulous to define at what point are you hitting "the Internet", I would certainly say that resolving DNS is too early in the process. It is very common when a network is down for DNS to still resolve.Manly

© 2022 - 2024 — McMap. All rights reserved.