Отримання імені хосту або IP-адреси в Ruby on Rails


80

Я в процесі ведення програми Ruby on Rails і шукаю простий спосіб знайти ім’я хосту або IP-адресу вікна, в якому я перебуваю (оскільки це ВМ, а нові екземпляри можуть мати різні імена хостів або IP-адреси) . Чи є швидкий і простий спосіб зробити це в Ruby on Rails?

Редагувати: Відповідь нижче є правильною, але роз'яснення, надане Крейгом, є корисним (див. Також посилання у відповіді):

Код [нижче] НЕ встановлює з'єднання та не надсилає жодних пакетів (до 64.233.187.99, що є google). Оскільки UDP є протоколом без стану, Connect () просто робить системний виклик, який з’ясовує, як маршрутизувати пакети на основі адреси та до якого інтерфейсу (і, отже, IP-адреси) він повинен прив’язуватися. addr () повертає масив, що містить сімейство (AF_INET), локальний порт та локальну адресу (що саме ми хочемо) сокета.

Відповіді:


50

З 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"

1
@ user422543 Відповідно до редагування у питанні вище, IP-адреса належить Google.
Topher Fangio

138

Ім'я хоста

Простий спосіб просто отримати ім’я хосту в Ruby:

require 'socket'
hostname = Socket.gethostname

Фішка полягає в тому, що це покладається на те, що хост знає своє власне ім'я, оскільки він використовує gethostnameабо unameсистемний виклик, і тому це не буде працювати для вихідної проблеми.

Функціонально це ідентично hostnameвідповіді, не викликаючи зовнішньої програми. Залежно від конфігурації апарата, ім’я хосту може бути повністю або не повністю кваліфікованим.


IP-адреса

Починаючи з ruby ​​1.9, ви також можете використовувати бібліотеку Socket, щоб отримати список локальних адрес. ip_address_listповертає масив об'єктів AddrInfo . Як ви виберете з нього, буде залежати від того, що ви хочете зробити, і скільки у вас є інтерфейсів, але ось приклад, який просто вибирає першу IP-адресу IPV4, яка не має петлі, як рядок:

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

Socket.gethostname не завжди повертає повне доменне ім’я. Використання 'hostname'.strip може бути більш надійним, якщо потрібне повне доменне ім'я.
Тревіс Ведмідь

Розетка. gethostname, по- видимому , не завжди стабільна, переглядати коментарі stackoverflow.com/q/14112955/32453
rogerdpack

Офіційна сторінка документа: ruby-doc.org/stdlib/libdoc/socket/rdoc/…
HarlemSquirrel

24

Спробуйте це:

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

4
Мені подобається Socket.gethostname за чистоту, але для простого пошуку в системі, де ти знаєш hostname, що буде працювати, ти не можеш перемогти його для простоти
Дейв Смілі,

ви також можете зробити uname -n.sub (/\..*/, '')
Тіло

13

Сервер зазвичай має більше одного інтерфейсу, принаймні один приватний та один загальнодоступний.

Оскільки всі відповіді тут стосуються цього простого сценарію, більш чистий спосіб - запитати у 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, що використовуються для фільтрування необхідної адреси інтерфейсу.


9

Ця IP-адреса, що використовується тут, є адресою Google, але ви можете використовувати будь-яку доступну IP-адресу.

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

8

Найпростіший - host_with_portу controller.rb

host_port= request.host_with_port

2
недоліком є ​​те, що для доступу до запиту ви повинні бути в контролері .. але гарна ідея!
Тіло

Здається, що інші відповіді - це просто хакі, тоді як це робить це правильно. Чому під ними поховано?
tbodt

2

Прийнята відповідь працює, але для кожного запиту потрібно створити сокет, і він не працює, якщо сервер знаходиться в локальній мережі та / або не підключений до Інтернету. Нижче, я вважаю, завжди буде працювати, оскільки він аналізує заголовок запиту.

request.env["SERVER_ADDR"]

3
OP фактично не сказав, що вони мали доступ до об'єкта запиту в той момент, коли йому потрібна IP-адреса. Рішення на базі Socket є більш загальними
Chris McCauley

2

Помістіть виділену частину в зворотні позначки:

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

Або просто request.hostякщо вам байдуже, це IP або ні.


2

Подібно до відповіді з 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']

1

Швидше за все, ви виявите кілька IP-адрес на кожному комп'ютері (127.0.0.1, 192.168.0.1 тощо). Якщо ви використовуєте * NIX як свою ОС, я б запропонував використовуватиhostname , а потім запустити пошук DNS на цьому. Ви повинні мати можливість використовувати / etc / hosts для визначення локального імені хосту для перетворення на IP-адресу для цього комп'ютера. Існує подібна функціональність у Windows, але я не використовував її, оскільки Windows 95 була кривавою.

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


WhatIsMyIP.com не працюватиме, якщо немає зовнішнього доступу до Інтернету.
Олов'яна людина

1
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виводиться в інший садиб у ваших системах, ви отримаєте різні результати для ІР. Пошук імені хосту повинен бути твердим, як Sears.


0

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

remote_ip ()

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

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


Це дає вам IP-адресу користувача, що видає запит на програму Rails, а не IP-адресу машини, на якій запущена програма Rails.
jsears
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.