Получение имени хоста или IP в Ruby on Rails

Я нахожусь в процессе обслуживания приложения Ruby on Rails и ищу простой способ найти имя хоста или IP-адрес ящика, на котором я работаю (так как это виртуальная машина и новые экземпляры могут иметь разные имена хостов или IP-адреса), Есть ли быстрый и простой способ сделать это в Ruby on Rails?

Изменить: Ответ ниже является правильным, но предоставленное Крейгом разъяснение полезно (см. Также предоставленную ссылку в ответе):

Код [ниже] НЕ устанавливает соединение и не отправляет какие-либо пакеты (на 64.233.187.99, который является Google). Поскольку UDP является протоколом без сохранения состояния, connect () просто выполняет системный вызов, который выясняет, как маршрутизировать пакеты на основе адреса и с каким интерфейсом (и, следовательно, IP-адресом), с которым он должен связываться. addr() возвращает массив, содержащий семейство (AF_INET), локальный порт и локальный адрес (что мы и хотим) сокета.

12 ответов

Решение

От 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"

Hostname

Простой способ получить имя хоста в Ruby:

require 'socket'
hostname = Socket.gethostname

Уловка в том, что это зависит от хоста, который знает свое имя, потому что он использует gethostname или же uname системный вызов, поэтому он не будет работать для исходной проблемы.

Функционально это идентично hostname Ответ, без вызова внешней программы. Имя хоста может быть или не быть полностью определенным, в зависимости от конфигурации машины.


Айпи адрес

Начиная с ruby ​​1.9, вы также можете использовать библиотеку Socket для получения списка локальных адресов. ip_address_list возвращает массив объектов AddrInfo. То, как вы выберете его, будет зависеть от того, что вы хотите сделать, и от того, сколько интерфейсов у вас есть, но вот пример, который просто выбирает первый IP-адрес без обратной связи в виде строки:

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

Попробуй это:

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

Сервер обычно имеет более одного интерфейса, по крайней мере, один частный и один общедоступный.

Поскольку все ответы здесь имеют дело с этим простым сценарием, более чистый способ - спросить у 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, используемые для фильтрации требуемого адреса интерфейса.

Самый простой host_with_port в controller.rb

host_port= request.host_with_port

Этот IP-адрес, используемый здесь, принадлежит Google, но вы можете использовать любой доступный IP-адрес.

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

Аналогично ответу с использованием hostname, используя внешний uname команда в UNIX/LINUX:

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']

Принятый ответ работает, но вы должны создать сокет для каждого запроса, и он не работает, если сервер находится в локальной сети и / или не подключен к Интернету. Я полагаю, что приведенное ниже будет работать всегда, так как оно выполняет синтаксический анализ заголовка запроса.

request.env["SERVER_ADDR"]

Поместите выделенную часть в кавычки:

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

Или просто request.host если вам все равно, IP это или нет.

Скорее всего, у вас будет несколько IP-адресов на каждом компьютере (127.0.0.1, 192.168.0.1 и т. Д.). Если вы используете *NIX в качестве своей ОС, я бы предложил использовать hostname, а затем запустить DNS посмотреть на это. Вы должны иметь возможность использовать /etc/hosts, чтобы определить локальное имя хоста для разрешения IP-адреса для этого компьютера. В Windows есть похожая функциональность, но я не использовал ее, так как Windows 95 была передовой.

Другим вариантом может быть поиск службы поиска, например WhatIsMyIp.com. Эти парни ответят вам вашим реальным IP-адресом. Это также то, что вы можете легко настроить с помощью сценария Perl на локальном сервере, если хотите. Я полагаю, что примерно три строки кода для вывода удаленного IP-адреса из%ENV должны вас охватить.

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.

Попробуйте: Request.remote_ip

remote_ip ()

Определить исходящий IP-адрес. REMOTE_ADDR - это стандарт, но он потерпит неудачу, если пользователь находится за прокси-сервером. HTTP_CLIENT_IP и / или HTTP_X_FORWARDED_FOR устанавливаются прокси, поэтому проверьте их, если REMOTE_ADDR является прокси. HTTP_X_FORWARDED_FOR может быть списком с разделителями-запятыми в случае нескольких цепочек прокси; последний недоверенный адрес - это исходящий IP.

Обновление: Ой, извините, я неправильно прочитал документацию.

Другие вопросы по тегам