我终于设法修复了我的软件中的ipv6支持。不幸的是,现在它在每台仅限ipv4的计算机上崩溃。这是错误的子例程:
sub init
{
my ($self, %opts) = @_;
# server options defaults
my %defaults = (StartBackground => 0, ServerPort => 3000);
# set options or use defaults
map { $self->{$_} = (exists $opts{$_} ? $opts{$_} : $defaults{$_}) }
keys %defaults;
$self->{'server'} = HTTP::AppServer::Base->new($self->{'ServerPort'}, Socket::AF_INET6);
return $self;
}
这里的问题出在倒数第二行:
$self->{'server'} = HTTP::AppServer::Base->new($self->{'ServerPort'}, Socket::AF_INET6);
与 ipv4 唯一的机器一样,它抱怨不支持的地址系列(这是传递给 new
函数的第二个参数)而死亡。
基本上,我需要做的是:
if (it_supports_ipv6()) {
$self->{'server'} = HTTP::AppServer::Base->new($self->{'ServerPort'}, Socket::AF_INET6);
}
else {
$self->{'server'} = HTTP::AppServer::Base->new($self->{'ServerPort'});
}
但是如何实现像it_supports_ipv6()
这样的功能呢?
我尝试使用以下语法eval
,但它不起作用:
my $ipv6_success = eval { $self->{'server'} = HTTP::AppServer::Base->new($self->{'ServerPort'}, Socket::AF_INET6); };
if (!defined($ipv6_success)) {
$self->{'server'} = HTTP::AppServer::Base->new($self->{'ServerPort'});
}
逻辑是我已经eval
文档中读到,如果表达式导致程序死亡,它会返回undef
。
我正在一台 Linux 机器上工作。
不要相信 Paranoid::Network::Socket
中的 has_ipv6()
函数。它返回误报,因为它只是检查Perl是否支持它,但这还不够(例如,系统可能缺少加载ipv6内核模块)。
我最终得到了以下功能,它似乎工作正常。
use IO::Socket::IP;
sub supports_ipv6 {
my $has_ipv6;
eval {
$has_ipv6 = IO::Socket::IP->new (
Domain => PF_INET6,
LocalHost => '::1',
Listen => 1 ) or die;
};
if ($@) {
return 0;
}
else {
return 1;
}
}
您可以通过以下eval
来检测AF_INET6
常数的存在:
use constant HAS_AF_INET6 => defined eval { Socket::AF_INET6() };
但这还不够;仅仅因为操作系统支持该常量并不意味着该特定机器支持它。您必须测试整个socket()
和bind()
操作是否正常工作。为此,您仍然希望以某种方式对实际的对象构造函数进行错误检测。