Pobieranie nazwy hosta lub adresu IP w Ruby on Rails

80

Jestem w trakcie utrzymywania aplikacji Ruby on Rails i szukam łatwego sposobu na znalezienie nazwy hosta lub adresu IP skrzynki, w której się znajduję (ponieważ jest to maszyna wirtualna, a nowe instancje mogą mieć różne nazwy hostów lub adresy IP) . Czy istnieje szybki i łatwy sposób na zrobienie tego w Ruby on Rails?

Edycja: poniższa odpowiedź jest prawidłowa, ale wyjaśnienie podane przez Craiga jest przydatne (zobacz również link podany w odpowiedzi):

Kod [poniżej] NIE nawiązuje połączenia ani nie wysyła żadnych pakietów (do 64.233.187.99 czyli google). Ponieważ UDP jest protokołem bezstanowym, connect () po prostu wykonuje wywołanie systemowe, które określa, jak trasować pakiety na podstawie adresu i interfejsu (a tym samym adresu IP), z którym ma się wiązać. addr () zwraca tablicę zawierającą rodzinę (AF_INET), port lokalny i adres lokalny (o co nam chodzi) gniazda.

Chris Bunch
źródło

Odpowiedzi:

50

Z 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"
tytaniczny
źródło
1
@ user422543 Zgodnie ze zmianą w powyższym pytaniu adres IP należy do Google.
Topher Fangio
138

Nazwa hosta

Prosty sposób na uzyskanie nazwy hosta w Rubim to:

require 'socket'
hostname = Socket.gethostname

Problem polega na tym, że polega to na tym, że host zna swoją nazwę, ponieważ używa wywołania systemowego gethostnamelub uname, więc nie będzie działać w przypadku pierwotnego problemu.

Funkcjonalnie jest to identyczne z hostnameodpowiedzią, bez wywoływania programu zewnętrznego. Nazwa hosta może, ale nie musi, być w pełni kwalifikowana, w zależności od konfiguracji komputera.


Adres IP

Od wersji Ruby 1.9 możesz również użyć biblioteki Socket, aby uzyskać listę adresów lokalnych. ip_address_listzwraca tablicę obiektów AddrInfo . To, jak wybierzesz, będzie zależeć od tego, co chcesz zrobić i ile masz interfejsów, ale oto przykład, który po prostu wybiera pierwszy adres IPV4 bez sprzężenia zwrotnego jako ciąg:

require 'socket'
ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
Tim Peters
źródło
Socket.gethostname nie zawsze zwraca nazwę FQDN. Używanie „hostname” .strip może być bardziej niezawodne, jeśli wymagana jest nazwa FQDN.
Travis Bear
Gniazdo elektryczne. gethostname najwyraźniej nie zawsze jest stabilne, patrz komentarze stackoverflow.com/q/14112955/32453
rogerdpack
Oficjalna strona dokumentu: ruby-doc.org/stdlib/libdoc/socket/rdoc/…
HarlemSquirrel
24

Spróbuj tego:

host = `hostname`.strip # Get the hostname from the shell and removing trailing \n
puts host               # Output the hostname
John Topley
źródło
4
I jak socket.gethostname do czystości, ale dla prostego odnośnika w systemie, w którym wiesz hostnamejedzie do pracy, nie można pokonać go dla uproszczenia
Dave Smylie
możesz też zrobić uname -n.sub (/\..*/, '')
Tilo,
13

Serwer zazwyczaj ma więcej niż jeden interfejs, co najmniej jeden prywatny i jeden publiczny.

Ponieważ wszystkie odpowiedzi tutaj dotyczą tego prostego scenariusza, czystszym sposobem jest poproszenie Socket o prąd, ip_address_list()jak w:

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

Oba zwracają obiekt Addrinfo, więc jeśli potrzebujesz łańcucha, możesz użyć ip_address()metody, jak w:

ip= my_first_public_ipv4.ip_address unless my_first_public_ipv4.nil?

Możesz łatwo znaleźć bardziej odpowiednie rozwiązanie dla swojego przypadku, zmieniając metody Addrinfo używane do filtrowania wymaganego adresu interfejsu.

Claudio Floreani
źródło
9

Ten użyty tutaj adres IP należy do Google, ale możesz użyć dowolnego dostępnego adresu IP.

require "socket"
local_ip = UDPSocket.open {|s| s.connect("64.233.187.99", 1); s.addr.last}
DD-Doug
źródło
8

Najprostszy jest plik host_with_portcontroller.rb

host_port= request.host_with_port
Salil
źródło
2
Wadą jest to, że musisz być w kontrolerze, aby uzyskać dostęp do żądania ... ale dobry pomysł!
Tilo,
Wygląda na to, że inne odpowiedzi to tylko hacki, ale robi to we właściwy sposób. Dlaczego jest pod nimi zakopany?
tbodt
2

Zaakceptowana odpowiedź działa, ale musisz utworzyć gniazdo dla każdego żądania i nie działa, jeśli serwer znajduje się w sieci lokalnej i / lub nie jest połączony z Internetem. Poniżej, jak sądzę, zawsze będzie działać, ponieważ analizuje nagłówek żądania.

request.env["SERVER_ADDR"]
hacintosh
źródło
3
OP w rzeczywistości nie powiedział, że miał dostęp do obiektu żądania w punkcie, w którym potrzebuje adresu IP. Rozwiązania oparte
Chris McCauley,
2

Umieść podświetloną część w grawerach:

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

Lub po prostu request.hostnie obchodzi Cię, czy to adres IP, czy nie.

Sai
źródło
2

Podobnie jak w przypadku odpowiedzi przy hostnameużyciu unamepolecenia zewnętrznego w systemie UNIX / LINUX:

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

dla używanych adresów IP (twój komputer może mieć wiele interfejsów sieciowych), możesz użyć czegoś takiego:

 # 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']
Tilo
źródło
1

Prawdopodobnie będziesz mieć wiele adresów IP na każdym komputerze (127.0.0.1, 192.168.0.1 itd.). Jeśli używasz * NIX jako swojego systemu operacyjnego, sugerowałbym użyciehostname , a następnie uruchomienie wyszukiwania DNS. Powinieneś być w stanie użyć / etc / hosts do zdefiniowania lokalnej nazwy hosta, która będzie tłumaczona na adres IP tej maszyny. W systemie Windows jest podobna funkcjonalność, ale nie korzystałem z niej, ponieważ Windows 95 był krwawiącą krawędzią.

Inną opcją byłoby skorzystanie z usługi wyszukiwania, takiej jak WhatIsMyIp.com . Ci faceci przekażą Ci Twój prawdziwy adres IP. Jest to również coś, co możesz łatwo skonfigurować za pomocą skryptu Perl na lokalnym serwerze, jeśli wolisz. Uważam, że około 3 wierszy kodu do wyprowadzenia zdalnego adresu IP z% ENV powinno Cię pokryć.

Jack M.
źródło
WhatIsMyIP.com nie będzie działać, jeśli nie ma zewnętrznego dostępu do Internetu.
Tin Man
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}\ /)

Kilka odpowiedzi require 'socket'wygląda dobrze. Te z request.blah_blah_blah zakładają, że używasz Railsów.

IO powinno być dostępne przez cały czas. Jedyny problem z tym skryptem polegałby na tym, że gdybyś ifconfigbył wyprowadzany w innej rezydencji w twoim systemie, wtedy otrzymywałbyś różne wyniki dla adresu IP. Nazwa hosta powinna być solidna, jak Sears.

Kevin Krauss
źródło
0

try: Request.remote_ip

zdalne IP()

Określ pierwotny adres IP. REMOTE_ADDR jest standardem, ale zakończy się niepowodzeniem, jeśli użytkownik znajduje się za proxy. HTTP_CLIENT_IP i / lub HTTP_X_FORWARDED_FOR są ustawiane przez proxy, więc sprawdź je, jeśli REMOTE_ADDR jest proxy. HTTP_X_FORWARDED_FOR może być listą rozdzielaną przecinkami w przypadku wielu połączonych w łańcuch proxy; ostatni niezaufany adres to pierwotny adres IP.

Aktualizacja: Ups, przepraszam, że źle przeczytałem dokumentację.

Craig
źródło
Daje to adres IP użytkownika wysyłającego żądanie do aplikacji Rails, a nie adres IP maszyny, na której działa aplikacja Rails.
jsears