Как определить IP-адреса локальной машины из Perl?

есть ли чистый и независимый от ОС способ определения IP-адресов локальной машины из Perl?

до сих пор я нашел следующие решения:

  • проанализируйте вывод ifconfig и ipconfig (жесткие, разные версии windows имеют разные выходы ipconfig)

  • установить сетевое подключение к известному IP и изучить локальный IP-адрес сокета (не будет работать, если я не могу установить соединение и будет определить только один IP-адрес)

лучше предложение?

11 ответов


Net::адрес::IP:: Local выглядит многообещающе.

use Net::Address::IP::Local;

# Get the local system's IP address that is "en route" to "the internet":
my $address      = Net::Address::IP::Local->public;

в моем случае, мне нужно решение без каких-либо непрофильных зависимостей. Я придумал это после изучения кода в Net:: Address:: IP:: Local:

#!/usr/bin/env perl

use strict;
use warnings;

use IO::Socket::INET;

my $local_ip_address = get_local_ip_address();

print "$local_ip_address\n";

# This idea was stolen from Net::Address::IP::Local::connected_to()
sub get_local_ip_address {
    my $socket = IO::Socket::INET->new(
        Proto       => 'udp',
        PeerAddr    => '198.41.0.4', # a.root-servers.net
        PeerPort    => '53', # DNS
    );

    # A side-effect of making a socket connection is that our IP address
    # is available from the 'sockhost' method
    my $local_ip_address = $socket->sockhost;

    return $local_ip_address;
}

get_local_ip_address() должен возвращать ту же строку как Net::Address::IP::Local->public_ipv4.

при желании вы можете изменить PeerAddr атрибут (в аргументах конструктора для IO::Socket::INET) для локального DNS-сервера.


У вас также есть некоторые другие функции, включая ваше решение "установить сетевое подключение к известному IP-адресу и изучить локальный IP-адрес сокета".

в этом случае (установление сетевого подключения), однако, эта статья указывает, что:

нет такой вещи, как IP-адрес хоста.
Сетевые интерфейсы имеют IP-адреса, а не хосты, и один сетевой интерфейс может иметь много (виртуальных) IP-адресов. Этот подсистема маршрутизации операционной системы решает, какой сетевой интерфейс и IP-адрес использовать для подключения к удаленной машине.

Если ваша машина имеет только один внешний сетевой интерфейс, и этот интерфейс имеет только один IP-адрес, то этот адрес называется адресом машины, но это неверно.
Например, если машина подключена к VPN через виртуальный интерфейс, она будет использовать IP-адрес этого интерфейса для подключения к другой машине в VPN, не внешний IP-адрес

среди других решений: использование "Sys::Hostname"
(Работает, если Sys::Hostname придумывает разрешимое имя хоста)

use Sys::Hostname;
use Socket;
my($addr)=inet_ntoa((gethostbyname(hostname))[4]);
print "$addr\n";

для получения IP-адреса все интерфейсы, использовать IO:: интерфейс:: простой:

perl -MIO::Interface::Simple '-Esay $_->address for grep { $_->is_running && defined $_->address } IO::Interface::Simple->interfaces'

Если вас не интересует 127.0.0.1 (loopback), вы можете фильтровать по $_->is_loopback.


Perldoc имеет ответ на этот вопрос в FAQ ("perlfaq9")-использование различных модулей (которые являются частью стандартной библиотеки) или даже встроенной функции.


У меня был хороший успех с IO:: Interface на Linux и Solaris, и я думаю, что он даже работал на AIX, но я не могу вспомнить точно. Ковыряюсь вокруг. search.cpan.org, rt.cpan.org и различные сайты ActiveState, похоже, Io:: Interface может испытывать проблемы со сборкой в Windows. Я думаю, единственный способ узнать, доступен ли он,-это поиск io-интерфейса в PPM.


использовать WMI?

пример извлечения IP-адресов (в Powershell, но довольно ясно, что происходит)

пример доступа к WMI из Perl (не те же функции WMI, но снова Процесс достаточно ясен)

EDIT: после поиска в Google codesearch для Networkadapterconfiguration и языка "perl":

пример выглядит довольно много, что вам нужно

EDIT2: На самом деле код OCS, похоже, содержит код для большинства платформ, поэтому, хотя может не быть одного набора кода, который делает это, вы можете повторно использовать свои идеи. Это хоть под GPL,.

например, вот код Соляриса. Другие биты охватывают BSD, Linux, MacOS...



Net:: Address:: IP:: Local отлично работает, но поскольку оригинальный плакат запрашивает все локальные адреса, я думаю, что этот лучше:

http://www.perlmonks.org/?node_id=166951

Он отлично работал для меня с ActivePerl для Windows XP.


для windows я использую

foreach (split(/\r?\n/,`netstat -r`))
{
  next unless /^\s+0.0.0.0/;
  @S = split(/\s+/); 
  # $S[3] = Default Gateway
  # $S[4] = Main IP
}

первая строка, начинающаяся с 0.0.0.0-шлюз по умолчанию. Там может быть несколько шлюзов. Также полезны строки, начинающиеся с 255.255.255.255. netstat-r и печать маршрута одинаковы.

может быть адаптирован для OSX, Linux не так полезен.


я использовал комбинацию этих команд Linux, поэтому никакой зависимости от любого модуля perl.

hostname -i
hostname -I
ls /sys/class/net
ip -f inet addr show eth0| grep -Po 'inet \K[\d.]+'