【问题标题】:Getting the Hostname or IP in Ruby on Rails在 Ruby on Rails 中获取主机名或 IP
【发布时间】:2010-09-07 17:44:54
【问题描述】:

我正在维护一个 Ruby on Rails 应用程序,并且正在寻找一种简单的方法来查找我所在机器的主机名或 IP 地址(因为它是一个虚拟机并且新实例可能有不同的主机名或IP 地址)。在 Ruby on Rails 中是否有一种快速简便的方法来执行此操作?

编辑:下面的答案是正确的,但 Craig 提供的澄清很有用(另请参阅答案中提供的链接):

[下面的]代码不会 连接或发送任何数据包(到 64.233.187.99 是谷歌)。由于 UDP 是无状态协议 connect() 只是进行系统调用 弄清楚如何路由数据包 基于地址和什么 接口(以及 IP 地址) 它应该绑定到。 addr() 返回一个 包含系列 (AF_INET) 的数组, 本地端口和本地地址(其中 是我们想要的)socket。

【问题讨论】:

    标签: ruby networking


    【解决方案1】:

    主机名

    在 Ruby 中获取主机名的简单方法是:

    require 'socket'
    hostname = Socket.gethostname
    

    问题在于,这依赖于知道自己名称的主机,因为它使用gethostnameuname 系统调用,因此它不适用于原始问题。

    在功能上这与hostname 答案相同,无需调用外部程序。主机名可能是完全限定的,也可能不是完全限定的,这取决于机器的配置。


    IP 地址

    从 ruby​​ 1.9 开始,您还可以使用 Socket 库来获取本地地址列表。 ip_address_list 返回 AddrInfo 对象的数组。如何从中选择取决于您想要做什么以及您有多少接口,但这里有一个示例,它只是选择第一个非环回 IPV4 IP 地址作为字符串:

    require 'socket'
    ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
    

    【讨论】:

    【解决方案2】:

    来自coderrr.wordpress.com

    require 'socket'
    
    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 '64.233.187.99', 1
        s.addr.last
      end
    ensure
      Socket.do_not_reverse_lookup = orig
    end
    
    # irb:0> local_ip
    # => "192.168.0.127"
    

    【讨论】:

    • @user422543 根据上述问题的编辑,IP 地址属于 Google。
    【解决方案3】:

    试试这个:

    host = `hostname`.strip # Get the hostname from the shell and removing trailing \n
    puts host               # Output the hostname
    

    【讨论】:

    • 我喜欢 Socket.gethostname 的纯粹性,但是对于在您知道 hostname 将起作用的系统上进行简单查找,您无法简单地击败它
    • 你也可以uname -n.sub(/\..*/,'')
    【解决方案4】:

    一台服务器通常有多个接口,至少一个私有接口和一个公共接口。

    由于这里的所有答案都针对这个简单的场景,因此更简洁的方法是向 Socket 询问当前的ip_address_list(),如下所示:

    require 'socket'
    
    def my_first_private_ipv4
      Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
    end
    
    def my_first_public_ipv4
      Socket.ip_address_list.detect{|intf| intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast? and !intf.ipv4_private?}
    end
    

    两者都返回一个 Addrinfo 对象,所以如果你需要一个字符串,你可以使用ip_address() 方法,如:

    ip= my_first_public_ipv4.ip_address unless my_first_public_ipv4.nil?
    

    更改用于过滤所需接口地址的 Addrinfo 方法,您可以轻松找到更适合您的情况的解决方案。

    【讨论】:

      【解决方案5】:

      最简单的是controller.rb中的host_with_port

      host_port= request.host_with_port
      

      【讨论】:

      • 缺点是你必须在控制器中才能访问请求。但好主意!
      • 似乎其他答案只是黑客,而这样做是正确的。为什么埋在他们下面?
      【解决方案6】:

      此处使用的此 IP 地址是 Google 的,但您可以使用任何可访问的 IP。

      require "socket"
      local_ip = UDPSocket.open {|s| s.connect("64.233.187.99", 1); s.addr.last}
      

      【讨论】:

        【解决方案7】:

        类似于使用hostname 的答案,在UNIX/LINUX 上使用外部uname 命令:

        hostname = `uname -n`.chomp.sub(/\..*/,'')  # stripping off "\n" and the network name if present
        

        对于正在使用的 IP 地址(您的机器可能有多个网络接口), 你可以使用这样的东西:

         # on a Mac:
         ip_addresses = `ifconfig | grep 'inet ' | grep -v 127.0.0.1 | cut -d' ' -f 2`.split
         => ['10.2.21.122','10.8.122.12']
        
         # on Linux:
         ip_addresses = `ifconfig -a | grep 'inet ' | grep -v 127.0.0.1 | cut -d':' -f 2 | cut -d' ' -f 1`.split
         => ['10.2.21.122','10.8.122.12']
        

        【讨论】:

          【解决方案8】:

          接受的答案有效,但您必须为每个请求创建一个套接字,如果服务器位于本地网络上和/或未连接到 Internet,则它不起作用。我相信下面的内容将始终有效,因为它正在解析请求标头。

          request.env["SERVER_ADDR"]
          

          【讨论】:

          • OP 实际上并没有说他们可以在他需要 IP 地址的地方访问请求对象。基于 Socket 的解决方案更通用
          【解决方案9】:

          将突出显示的部分放在反引号中:

          `dig #{request.host} +short`.strip # dig gives a newline at the end
          

          如果你不在乎它是否是 IP,或者只是 request.host

          【讨论】:

            【解决方案10】:

            您可能会发现自己在每台机器上都有多个 IP 地址(127.0.0.1、192.168.0.1 等)。如果您使用*NIX 作为您的操作系统,我建议使用hostname,然后运行DNS 查找。您应该能够使用 /etc/hosts 来定义本地主机名以解析为该机器的 IP 地址。 Windows 上有类似的功能,但我没有使用过,因为 Windows 95 是最前沿的。

            另一种选择是使用WhatIsMyIp.com 之类的查找服务。这些家伙会将您的真实 IP 地址返还给您。如果您愿意,这也是您可以在本地服务器上使用 Perl 脚本轻松设置的内容。我相信从 %ENV 输出远程 IP 的 3 行左右的代码应该涵盖你。

            【讨论】:

            • 如果没有外部互联网访问,WhatIsMyIP.com 将无法工作。
            【解决方案11】:
            io = IO.popen('hostname')
            hostname = io.readlines
            
            io = IO.popen('ifconfig')
            ifconfig = io.readlines
            ip = ifconfig[11].scan(/\ \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\ /)
            

            require 'socket' 的两个答案看起来不错。带有 request.blah_blah_blah 的那些 假设您正在使用 Rails。

            IO 应该始终可用。此脚本的唯一问题是,如果ifconfig 在您的系统上以不同的方式输出,那么您将获得不同的 IP 结果。主机名查找应该像 Sears 一样可靠。

            【讨论】:

              【解决方案12】:

              试试:Request.remote_ip

              remote_ip()

              确定原始 IP 地址。 REMOTE_ADDR 是标准但会 如果用户在代理后面,则失败。 HTTP_CLIENT_IP 和/或 HTTP_X_FORWARDED_FOR 由代理设置,因此请检查这些是否 REMOTE_ADDR 是一个代理。 HTTP_X_FORWARDED_FOR 可能是逗号分隔的 在多个链式代理的情况下列出;最后一个地址 不受信任的是原始 IP。

              更新: 糟糕,抱歉我误读了文档。

              【讨论】:

              • 这为您提供了向 Rails 应用程序发出请求的用户的 IP 地址,而不是运行 Rails 应用程序的机器的 IP 地址。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-04-12
              • 1970-01-01
              • 2011-09-10
              • 2010-09-07
              • 2015-07-08
              • 2013-11-09
              • 2022-01-18
              相关资源
              最近更新 更多