如何使用Perl确定本地计算机的IP地址?

16

是否有干净且与操作系统无关的方法来从Perl中确定本地机器的IP地址?

到目前为止,我找到了以下解决方案:

  • 解析 ifconfig 和 ipconfig 的输出结果(很麻烦,不同版本的Windows具有不同的ipconfig输出结果)

  • 连接到已知的IP地址并检查套接字的本地IP地址(如果无法建立连接,则无法使用此方法,并且只能确定一个IP地址)

有更好的建议吗?


神奇的数字是127.0.0.1。 - Toon Krijthe
2
这不是我需要的。我只想以自定义形式打印出机器的IP地址,我不想使用这些地址。 - Zizzencs
11个回答

18

您还有一些其他选项,包括您提出的“建立与已知IP的网络连接并检查套接字的本地IP地址”解决方案。

然而,在这种情况下(建立网络连接),该文章指出:

不存在主机IP地址的概念。
网络接口具有IP地址,而不是主机,单个网络接口可以有许多(虚拟)IP地址。操作系统路由子系统决定使用哪个网络接口和IP地址连接到远程计算机。

如果您的计算机只有一个外部网络接口,并且此接口只有一个IP地址,则通常称此IP地址为计算机地址,但这是不准确的。
例如,如果计算机通过虚拟接口连接到VPN,则会使用此界面的IP地址连接到VPN上的另一台计算机,而不是外部IP地址。

在其他解决方案中:Sys::Hostname - 如果它能够生成可解析的主机名,则有效。

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

这些也是不适用于所有情况的好解决方案。如果没有更好的解决方案,我将创建一个结合它们的定制解决方案。谢谢。 - Zizzencs
1
@zb226 感谢您的编辑,非常感谢。 - VonC

18

Net::Address::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;

新链接 http://search.cpan.org/~jmehnle/Net-Address-IP-Local-0.1.2/lib/Net/Address/IP/Local.pm - Joel Berger
使链接版本独立化;-) - Leon Timmermans
1
@zizzencs 我不明白为什么你接受了这个答案,因为你要求返回机器的所有IP地址。而这个答案只返回了一个。 - dolmen

15

在我的情况下,我需要一个没有任何非核心依赖的解决方案。在研究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相同的字符串。

如果需要,您可以将IO::Socket::INET构造函数中的PeerAddr属性更改为本地DNS服务器。


1
-1 不建议使用复制/粘贴的方式进行Perl开发。 - dolmen
1
@dolmen 同意。如果能有所帮助,我编写的脚本被用作cron作业,并部署到开发机器上以保持DNS记录活动状态。如果我重新考虑它,我会考虑将Net::Address::IP::Local打包到脚本中来进行fatpacking。 >=D - Tommy Stanton
3
@dolmen 轻点 -1。这样的做法有助于那些不熟悉 Perl 只想快速完成任务的人们。 - darda
1
滥用根域名服务器是不可取的,因为这些地址可能会发生变化,从而导致系统不稳定。 - Terry Burton

7

要获取所有接口的IP地址,请使用IO::Interface::Simple

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

如果您不关注127.0.0.1(回环),则可以通过$_->is_loopback进行过滤。


3

Perldoc在其FAQ中(“perlfaq9”)有一个与此问题相关的答案 - 使用不同的模块(这些模块是标准库的一部分)甚至是内置函数。


1

我在Linux和Solaris上使用IO::Interface非常成功,我认为它甚至可以在AIX上工作,但我不能确定。在search.cpan.org、rt.cpan.org和ActiveState的各个网站上搜索,看起来IO::Interface可能在Windows上遇到了构建问题。我想唯一知道它是否可用的方法是在PPM中搜索io-interface。



0

使用WMI?

提取IP地址示例(使用Powershell,但很清楚正在发生什么)

从Perl访问WMI的示例(不是相同的WMI函数,但是过程再次相当清晰)

编辑:在Google codesearch上搜索Networkadapterconfiguration和语言“perl”后:

示例看起来就是你需要的

编辑2:实际上,OCS代码似乎包含了大多数平台执行此操作的代码,因此虽然可能没有一组代码可以执行此操作,但您可以重用它们的想法。然而,它是GPL许可的。

例如,这里是Solaris代码。其他部分覆盖了BSD、Linux、MacOS等。


看起来很有前途,但据我所知,大多数Linux系统上都没有WMI。当然,您可以使用OpenPegasus,但这对于这个问题来说有点过于庞大了。 - Zizzencs
不,WMI不适用。看起来你可能需要根据操作系统类型切换,并编写不同的代码。 - The Archetypal Paul
如果没有其他办法,我会这样做。谢谢你的回答。 - Zizzencs
Google Code 搜索链接已经失效。 - dolmen
是的,Google Code Search已经不存在了。我没有更新的资源。 - The Archetypal Paul

0

在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和route print是相同的。

可以适用于OSX,但对Linux不太有帮助。


0

Net::Address::IP::Local 可以正常工作,但由于原帖作者要求获取所有本地地址,我认为这个更好:

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

我使用适用于Windows XP的ActivePerl,它对我很有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接