Lấy tên máy chủ hoặc IP trong Ruby on Rails


80

Tôi đang trong quá trình bảo trì ứng dụng Ruby on Rails và đang tìm một cách dễ dàng để tìm tên máy chủ hoặc địa chỉ IP của hộp tôi đang sử dụng (vì đó là máy ảo và các phiên bản mới có thể có tên máy chủ hoặc địa chỉ IP khác nhau) . Có cách nào nhanh chóng và dễ dàng để thực hiện việc này trong Ruby on Rails không?

Chỉnh sửa: Câu trả lời bên dưới là đúng nhưng phần làm rõ mà Craig cung cấp là hữu ích (xem liên kết được cung cấp trong câu trả lời):

Mã [bên dưới] KHÔNG tạo kết nối hoặc gửi bất kỳ gói nào (tới 64.233.187.99 là google). Vì UDP là một giao thức không trạng thái, nên kết nối () chỉ thực hiện một lệnh gọi hệ thống tìm ra cách định tuyến các gói dựa trên địa chỉ và giao diện (và do đó là địa chỉ IP) mà nó sẽ liên kết. addr () trả về một mảng chứa họ (AF_INET), cổng cục bộ và địa chỉ cục bộ (đó là những gì chúng ta muốn) của ổ cắm.

Câu trả lời:


50

Từ 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 Theo chỉnh sửa trong câu hỏi ở trên, địa chỉ IP thuộc về Google.
Topher Fangio

137

Tên máy chủ

Một cách đơn giản để lấy tên máy chủ trong Ruby là:

require 'socket'
hostname = Socket.gethostname

Vấn đề là điều này phụ thuộc vào việc máy chủ biết tên riêng của nó vì nó sử dụng lệnh gọi gethostnamehoặc unamehệ thống, vì vậy nó sẽ không hoạt động cho sự cố ban đầu.

Về mặt chức năng, điều này giống với hostnamecâu trả lời mà không cần gọi một chương trình bên ngoài. Tên máy chủ có thể đủ tiêu chuẩn hoặc không, tùy thuộc vào cấu hình của máy.


Địa chỉ IP

Kể từ ruby ​​1.9, bạn cũng có thể sử dụng thư viện Socket để lấy danh sách các địa chỉ cục bộ. ip_address_listtrả về một mảng các đối tượng AddrInfo . Cách bạn chọn từ nó sẽ phụ thuộc vào những gì bạn muốn làm và số lượng giao diện bạn có, nhưng đây là một ví dụ chỉ đơn giản là chọn địa chỉ IP IPV4 không lặp lại đầu tiên dưới dạng chuỗi:

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

Socket.gethostname không phải lúc nào cũng trả về FQDN. Sử dụng 'hostname' .strip có thể đáng tin cậy hơn nếu bạn muốn FQDN.
Travis Bear

Ổ cắm. gethostname dường như không phải lúc nào cũng ổn định, hãy xem nhận xét stackoverflow.com/q/14112955/32453
rogerdpack


24

Thử đi:

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

4
Tôi như Socket.gethostname cho sự thuần khiết, nhưng đối với một tra cứu đơn giản trên một hệ thống mà bạn biết hostnamesẽ làm việc, bạn không thể đánh bại nó vì đơn giản
Dave Smylie

bạn cũng có thể làm uname -n.sub (/\..*/, '')
Tilo

13

Một máy chủ thường có nhiều hơn một giao diện, ít nhất một giao diện riêng tư và một giao diện chung.

Vì tất cả các câu trả lời ở đây đều giải quyết tình huống đơn giản này, nên một cách rõ ràng hơn là hỏi Socket cho dòng điện ip_address_list()như trong:

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

Cả hai đều trả về một đối tượng Addrinfo, vì vậy nếu bạn cần một chuỗi, bạn có thể sử dụng ip_address()phương thức, như trong:

ip= my_first_public_ipv4.ip_address unless my_first_public_ipv4.nil?

Bạn có thể dễ dàng tìm ra giải pháp phù hợp hơn cho trường hợp của mình bằng cách thay đổi các phương thức Addrinfo được sử dụng để lọc địa chỉ giao diện được yêu cầu.


9

Địa chỉ IP được sử dụng ở đây là của Google, nhưng bạn có thể sử dụng bất kỳ IP nào có thể truy cập được.

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

8

Đơn giản nhất là host_with_porttrong controller.rb

host_port= request.host_with_port

2
nhược điểm là bạn phải ở trong bộ điều khiển để truy cập yêu cầu .. nhưng ý kiến ​​hay!
Tilo

Có vẻ như các câu trả lời khác chỉ là hack, trong khi điều này diễn ra đúng cách. Tại sao nó lại bị chôn vùi dưới họ?
tbodt

2

Câu trả lời được chấp nhận hoạt động nhưng bạn phải tạo một ổ cắm cho mọi yêu cầu và nó không hoạt động nếu máy chủ nằm trên mạng cục bộ và / hoặc không được kết nối với internet. Dưới đây, tôi tin rằng sẽ luôn hoạt động vì nó đang phân tích cú pháp tiêu đề yêu cầu.

request.env["SERVER_ADDR"]

3
OP không thực sự nói rằng họ có quyền truy cập vào đối tượng yêu cầu tại điểm mà anh ta cần địa chỉ IP. Các giải pháp socket dựa mang tính tổng quát hơn
Chris McCauley

2

Đặt phần được đánh dấu trong dấu gạch ngược:

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

Hoặc chỉ request.hostkhi bạn không quan tâm đó có phải là IP hay không.


2

Tương tự như câu trả lời bằng cách sử hostnamedụng unamelệnh bên ngoài trên UNIX / LINUX:

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

đối với các địa chỉ IP đang sử dụng (máy của bạn có thể có nhiều giao diện mạng), bạn có thể sử dụng một cái gì đó như sau:

 # 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

Bạn có thể sẽ thấy mình có nhiều địa chỉ IP trên mỗi máy (127.0.0.1, 192.168.0.1, v.v.). Nếu bạn đang sử dụng * NIX làm hệ điều hành của mình, tôi khuyên bạn nên sử dụng hostnamevà sau đó chạy DNS tra cứu điều đó. Bạn sẽ có thể sử dụng / etc / hosts để xác định tên máy cục bộ để phân giải thành địa chỉ IP cho máy đó. Có chức năng tương tự trên Windows, nhưng tôi đã không sử dụng nó vì Windows 95 là một thế giới mới.

Tùy chọn khác sẽ là sử dụng một dịch vụ tra cứu như WhatIsMyIp.com . Những kẻ này sẽ trả lại địa chỉ IP trong thế giới thực của bạn cho bạn. Đây cũng là thứ mà bạn có thể dễ dàng thiết lập bằng tập lệnh Perl trên máy chủ cục bộ nếu muốn. Tôi tin rằng 3 dòng hoặc lâu hơn mã để xuất IP từ xa từ% ENV sẽ bao gồm bạn.


WhatIsMyIP.com sẽ không hoạt động nếu không có truy cập internet bên ngoài.
the 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}\ /)

Một số câu trả lời có require 'socket'vẻ tốt. Những cái có request.blah_blah_blah giả sử rằng bạn đang sử dụng Rails.

IO nên luôn sẵn sàng. Vấn đề duy nhất với tập lệnh này là nếu ifconfigđược xuất ở một trang viên khác trên hệ thống của bạn, thì bạn sẽ nhận được các kết quả khác nhau cho IP. Tên máy chủ tra cứu phải chắc chắn là Sears.


0

thử: Request.remote_ip

remote_ip ()

Xác định địa chỉ IP gốc. REMOTE_ADDR là tiêu chuẩn nhưng sẽ không thành công nếu người dùng sử dụng proxy. HTTP_CLIENT_IP và / hoặc HTTP_X_FORWARDED_FOR được đặt bởi proxy, vì vậy hãy kiểm tra những điều này nếu REMOTE_ADDR là proxy. HTTP_X_FORWARDED_FOR có thể là danh sách được phân tách bằng dấu phẩy trong trường hợp có nhiều proxy chuỗi; địa chỉ cuối cùng không đáng tin cậy là IP gốc.

Cập nhật: Rất tiếc, xin lỗi tôi đã đọc nhầm tài liệu.


Điều này cung cấp cho bạn địa chỉ IP của người dùng gửi yêu cầu đến ứng dụng Rails, không phải địa chỉ IP của máy chạy ứng dụng Rails.
jsears
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.