3

我终于设法在我的软件中修复了对 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'});
}

逻辑是我在evaldoc 中读到,undef如果表达式导致程序死亡,它会返回。

我正在使用 Linux 机器。

4

2 回答 2

1

您可以通过以下方式检测AF_INET6常量的存在eval

use constant HAS_AF_INET6 => defined eval { Socket::AF_INET6() };

但这还不够。仅仅因为操作系统支持该常量并不意味着这台特定的机器支持它。您必须测试整个操作是否正常工作socket()bind()为此,您仍然希望以某种方式错误检测实际的对象构造函数。

于 2012-09-16T17:50:47.650 回答
1

不要相信has_ipv6(). Paranoid::Network::Socket它返回误报,因为它只是检查 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;
    }
}
于 2012-09-20T20:07:25.630 回答