如何在Ruby中获取计算机的IP地址,而不依赖于其他IP地址?

29

我已经到处搜索了,但他们的解决方案都需要某种形式的IP地址。以下是我找到的解决方案。

    require 'socket'
#METHOD 1
    ip = IPSocket.getaddress(Socket.gethostname)
    puts ip 

#METHOD 2
    host = Socket.gethostname
    puts host

#METHOD 3(uses Google's address)
    ip = UDPSocket.open {|s| s.connect("64.233.187.99", 1); s.addr.last}
    puts ip

#METHOD 4(uses gateway address)
    def local_ip
      orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily

      UDPSocket.open do |s|
        s.connect '192.168.1.1', 1
        s.addr.last
      end
    ensure
      Socket.do_not_reverse_lookup = orig
    end

    ip=local_ip
    puts ip

它们都需要某人的IP地址。有没有不使用别人的IP地址的解决方案?最好是平台无关的。


2
第一个需要什么“某人的IP地址”?此外,谁说网关总是在192.168.1.1? - Matti Virkkunen
这个网址 http://rubygems.org/gems/system-getifaddrs 可能会有所帮助。 - alk
本地还是全球?(例如:192.168.1.23或75.75.75.64)? - Linuxios
1
方法1有什么问题? - Eugene Rourke
1
@EvgeniyRyzhkov:来自文档的原话(http://docs.python.org/2/library/socket.html):“*……如果您想知道当前机器的IP地址,您可能希望使用gethostbyname(gethostname())。此操作假定主机有有效的地址到主机映射,并且这种假设并不总是成立*”。请注意**最后七个单词**。 - alk
UDPSocket.connect(某人的IP)实际上并不连接,UDP因其无连接而闻名。 因此,使用他人的IP虽然不太优雅,但在功能上是无害的。 好吧,优雅确实有价值,但是在这里使用0.0.0.0或127.0.0.1,正如https://superuser.com/questions/698244/ip-address-that-is-the-equivalent-of-dev-null中的一些答案所建议的那样,在这里不起作用。 - Martin Dorey
5个回答

49

你寻找的解决方案难道不就是:

require 'socket'

addr_infos = Socket.ip_address_list

由于一台机器可以拥有多个接口和多个IP地址,因此此方法返回一个 Addrinfo 数组。

您可以这样获取确切的IP地址:

addr_infos.each do |addr_info|
  puts addr_info.ip_address
end

您可以进一步过滤列表,拒绝回环和私有地址,因为它们通常不是您感兴趣的内容,就像这样:

addr_infos.reject( &:ipv4_loopback? )
          .reject( &:ipv6_loopback? )
          .reject( &:ipv4_private? )

2
是的,这正是我所需要的。 :) - Piotrek Okoński
1
Ruby 1.8.7的Socket没有ip_address_list()。我也希望我不必关心。 - Martin Dorey
@MartinDorey :我向你表示慰问。但是你仍然可以使用Eugene Rourke的解决方案 - Itay Grudev

31

这是我多年来一直在生产环境中使用的:

require 'socket'
ip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
ip.ip_address

运行良好;已在 AWS 和传统托管上进行测试


据我所知,它在底层使用了 getifaddrs。另外,如果你正在寻找公共 IPv4,请参考 https://dev59.com/03VD5IYBdhLWcg3wO5ED#7809076 - rogerdpack

16
require 'socket'
Socket::getaddrinfo(Socket.gethostname,"echo",Socket::AF_INET)[0][3]

实际上非常像方法1


请查看我的关于使用 gethostname() 的评论,针对原始帖子(OP)。 - alk

1

由于主机没有默认的IP接口(实际上根本不需要任何IP接口),因此关于命名的所有假设都是模糊的,不一定成立。

gethostname()返回的值可以独立于任何IP设置进行定义,因此它不需要反映出有效的主机名,也不需要解析到任何IP地址。

从POSIX系统API的角度来看,测试可用性(IP)接口的唯一可靠函数是getifaddrs()函数,它返回所有接口及其参数的列表。

由于Ruby当前的Socket库似乎没有提供接口,因此基于gem的方法this (http://rubygems.org/gems/system-getifaddrs)似乎是唯一的选择。


Socket.ip_address_list 似乎使用 getifaddrs(尽管自此回答发布以来可能已更新)。顺便说一下。 - rogerdpack
实际上,路由表可以并且经常会指定默认接口。 - Thayne

0

1
这不会给你默认接口的网关IP地址,而不是默认接口的IP地址吗? - Thayne
兄弟,你粘贴了什么?这是默认网关,如果你有多个默认网关,你需要检查具有最低度量的那个。 - maxadamo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接