Perl套接字如何在Linux下解析主机名?
时间:2020-03-06 15:00:33 来源:igfitidea点击:
我有一个(据我所知)可以完美运行的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');打印inet_ntoa($ ret);
- 原始源代码可在Windows下运行
- 这是它应该如何工作的(即,它应该解析主机名),因为LWP尝试使用此行为(实际上,我通过尝试调试LWP不适用于我的原因偶然发现了该问题)
- 运行脚本不会发出DNS请求(因此它甚至都不会尝试解析名称)。已通过Wireshark验证
解决方案
确保我们有对帐单
use IO::Socket::INET;
在源代码的开头。如果不进行此操作,则可能会收到错误消息:
Can't locate object method "new" via package "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');
快速浏览一下,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,
的变通方法。
如果没有这种解决方法,上面的代码似乎试图使用Socket.pm中的inet_aton()来调用inet_aton(" hostname.com")`。这在Win32和Unix上都对我有效,所以我想这就是我们面临的问题。
有关inet_aton的源代码,请参见Socket.xs:
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",它可以正常工作。
我怀疑"多宿主"选项是不必要的破解,而其他一些问题是造成问题的根本原因。