Perl 套接字如何在 Linux 下解析主机名?
题
我有一个(据我所知)完美运行的 Linux 设置(Ubuntu 8.04),其中所有工具(nslookup、curl、wget、firefox 等)都能够解析地址。然而,下面的代码失败了:
$s = new IO::Socket::INET(
PeerAddr => 'stackoverflow.com',
PeerPort => 80,
Proto => 'tcp',
);
die "Error: $!\n" unless $s;
我验证了以下几点:
Perl 能够使用 gethostbyname 解析地址(即下面的代码有效):
my $ret = gethostbyname('stackoverflow.com'); print inet_ntoa($ret);
原始源代码在Windows下运行
- 这就是它应该如何工作(即它应该解析主机名),因为 LWP 尝试使用这种行为(事实上,我通过尝试调试为什么 LWP 不适合我而偶然发现了这个问题)
- 运行该脚本不会发出 DNS 请求(因此它甚至不会尝试解析该名称)。使用 Wireshark 验证
解决方案
快速浏览一下,以下代码来自 IO::Socket::INET
sub _get_addr {
my($sock,$addr_str, $multi) = @_;
my @addr;
if ($multi && $addr_str !~ /^\d+(?:\.\d+){3}$/) {
(undef, undef, undef, undef, @addr) = gethostbyname($addr_str);
} else {
my $h = inet_aton($addr_str);
push(@addr, $h) if defined $h;
}
@addr;
}
建议(如果您查看此代码的调用者)添加的解决方法 MultiHomed => 1,
到你的代码。
如果没有这种解决方法,上面的代码似乎会尝试调用 inet_aton("hostname.com")
使用 Socket.pm 中的 inet_aton()。这对我来说在 Win32 和 Unix 上都有效,所以我想这就是你的问题所在。
看 套接字.xs inet_aton的源代码:
void
inet_aton(host)
char * host
CODE:
{
struct in_addr ip_address;
struct hostent * phe;
if (phe = gethostbyname(host)) {
Copy( phe->h_addr, &ip_address, phe->h_length, char );
} else {
ip_address.s_addr = inet_addr(host);
}
ST(0) = sv_newmortal();
if(ip_address.s_addr != INADDR_NONE) {
sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address );
}
}
看起来 Perl gethostbyname() 比 C gethostbyname() 更适合您。
其他提示
你能否准确地告诉我们 如何 你的代码失败了?你那里有错误检查代码,但你还没有报告错误是什么!
我刚刚尝试了原始代码(在我的 Mac OS X 机器上添加了“use IO::Socket::INET”,并且工作正常。
我怀疑多宿主选项是不必要的黑客行为,而其他一些问题是问题的根本原因。
确保您有声明
use IO::Socket::INET;
在源代码的开头。如果您忽略这一点,您可能会收到错误消息:
无法通过以下方式找到对象方法“new” 包"IO:: Socket:: INET"
除此之外,您可以使用 Net::DNS::Resoler 验证 DNS 是否正常工作,请参阅更多信息 这里.
use Net::DNS;
my $res = Net::DNS::Resolver->new;
# Perform a lookup, using the searchlist if appropriate.
my $answer = $res->search('example.com');