Perl:检查套接字选项是否存在

时间:2010-02-09 09:09:03

标签: perl sockets network-programming

这是我之前提问的延续:

In Perl, how can I check for the existence of Socket options without generating warnings?

如果我运行以下代码,我会得到我期望的结果:

#!/usr/bin/perl -w
use strict;
use diagnostics;
use Socket qw(:all);

my %opts;

if ( defined( eval { SO_REUSEPORT } ) ) {
    $opts{'SO_REUSEPORT'}
        =  {opt_level =>SOL_SOCKET,opt_name=>SO_REUSEPORT,opt_print=>\&sock_str_flag};
} else {
    print "SO_REUSEPORT undefined\n";
    $opts{'SO_REUSEPORT'}
        =  {opt_level =>0,opt_name=>0,opt_print=>undef};
}
=head
# IPV6 options
if ( defined( eval { IPV6_DONTFRAG } ) ) {
    $opts{'IPV6_DONTFRAG'}
        =  {opt_level =>IPPROTO_IPV6,opt_name=>IPV6_DONTFRAG,opt_print=>\&sock_str_flag};
} else {
    print "IPV6_DONTFRAG undefined\n";
    $opts{'IPV6_DONTFRAG'}
        =  {opt_level =>0,opt_name=>0,opt_print=>undef};
}
=cut

输出:

anon@perl$ ./test.pl 
SO_REUSEPORT undefined

但如果我取消注释IPV6_DONTFRAG的块,我会得到:

Bareword "IPV6_DONTFRAG" not allowed while "strict subs" in use at ./test.pl line 17.
Bareword "IPV6_DONTFRAG" not allowed while "strict subs" in use at ./test.pl line 17.

为什么一个未定义的裸字导致barf而另一个没有?如何将错误传播出eval { }块?

修改

显然,SO_REUSEPORT以某种方式由Socket.pm导出,因为它位于@EXPORT数组中。显然它已被定义但使用它会抛出eval捕获的错误。

这仍然无法解释IPV6_DONTFRAG发生了什么。我想我需要自己定义它然后只需调用getsockopt来检查它是否受支持......

2 个答案:

答案 0 :(得分:4)

我建议这样写:

if ( defined( &IPV6_DONTFRAG ) ) {
    $opts{'IPV6_DONTFRAG'}
        =  {opt_level =>IPPROTO_IPV6,opt_name=>&IPV6_DONTFRAG,opt_print=>\&sock_str_flag};
} else {
    print "IPV6_DONTFRAG undefined\n";
    $opts{'IPV6_DONTFRAG'}
        =  {opt_level =>0,opt_name=>0,opt_print=>undef};
}

请注意opt_name的值中添加的&符号,它会因strict 'subs'而避开约束。

documentation for defined解释说:

  

您也可以使用defined(&func)检查是否已定义子例程&func。返回值不受&func的任何前向声明的影响。请注意,未定义的子例程可能仍然是可调用的:它的包可能有一个AUTOLOAD方法,使其在第一次被调用时就会存在 - 请参阅perlsub

例如,使用SO_BROADCAST

if (defined &SO_BROADCAST) {
  print "SO_BROADCAST = ", SO_BROADCAST, "\n";
}

我机器上的输出是

SO_BROADCAST = 6

答案 1 :(得分:0)

关于IPV6_DONTFRAG裸字问题,看起来Perl在编译时检查裸字,而不是运行时,如文档here所述。 Eval是一个吞下运行时错误的构造,所以它对你没有帮助。这就像试图通过将违规代码粘贴在try / catch块中来处理C ++中的语法错误。