这是我之前提问的延续:
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
来检查它是否受支持......
答案 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'
而避开约束。
您也可以使用
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 ++中的语法错误。