我终于设法修复了我的软件中的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
doc中读到如果表达式导致程序死亡,它返回undef
。
我正在使用Linux机器。
答案 0 :(得分:0)
您可以通过AF_INET6
检测eval
常数的存在:
use constant HAS_AF_INET6 => defined eval { Socket::AF_INET6() };
但这还不够;仅仅因为OS支持该常量并不意味着这个特定的机器支持它。您必须测试整个socket()
和bind()
操作是否也能正常运行。为此你仍然想以某种方式错误检测实际的对象构造函数。
答案 1 :(得分:0)
不要相信has_ipv6()
中的Paranoid::Network::Socket
功能。它返回false positive,因为它只是检查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;
}
}