问题描述
my $waitlist = IO::Select->new($self->{sock});
while($datalen < 9)
{
##timeout set as 50
if($waitlist->can_read($timeout || 0)) {
print_message(LOGLEVEL_TRACE,"INSIDE IF....",LOG_TAG);
$templen = $self->{sock}->sysread($tempdata,9 - $datalen);
} else {
print_message(LOGLEVEL_TRACE,"INSIDE ELSE....",LOG_TAG);
print_message(LOGLEVEL_TRACE,"B4 ERROR $!",LOG_TAG);
$templen = 0;
$! = EWOULDBLOCK;
}
print_message(LOGLEVEL_TRACE,"ERROR $!",LOG_TAG);
}
在上面的代码中,“ can_read”由于设备的不适当的ioctl而出错。想知道原因并进行修复。
解决方法
$!
仅在系统调用指示其设置了$!
后才有意义。
问题:
- 在使用系统调用集
$!
之前,您无需检查它。 - 您可以在感兴趣的系统调用与使用
print_message
之间调用$!
,并且print_message
肯定可以进行系统调用。
要注意的一件事是检查can_read
是否返回错误的方法真的很奇怪。
返回准备读取的句柄数组。
TIMEOUT
是返回空列表($!
不变)之前等待的最长时间,以秒为单位,可能是分数。如果未提供TIMEOUT
且未注册任何句柄,则该调用将无限期阻塞。发生错误时,将返回一个空列表,其中设置了$!
来指示错误。要区分超时和错误,请在调用此方法之前将$!
设置为零,并在返回空列表后进行检查。
替换
my $waitlist = IO::Select->new($self->{sock});
while($datalen < 9)
{
##timeout set as 50
if($waitlist->can_read($timeout || 0)) {
print_message(LOGLEVEL_TRACE,"INSIDE IF....",LOG_TAG);
$templen = $self->{sock}->sysread($tempdata,9 - $datalen);
} else {
print_message(LOGLEVEL_TRACE,"INSIDE ELSE....",LOG_TAG);
print_message(LOGLEVEL_TRACE,"B4 ERROR $!",LOG_TAG);
$templen = 0;
$! = EWOULDBLOCK;
}
print_message(LOGLEVEL_TRACE,"ERROR $!",LOG_TAG);
}
使用
my $waitlist = IO::Select->new($self->{sock});
while (length($tempdata) < 9) {
$! = 0;
my @handles = $waitlist->can_read($timeout || 0);
if ($!) { # Yuck,just about anywhere else,this would be wrong.
print_message(LOGLEVEL_TRACE,"SELECT FAILED: $!",LOG_TAG);
...abort...
}
if (!@handles) {
print_message(LOGLEVEL_TRACE,"SELECT FAILED: Timeout",LOG_TAG);
...abort...
}
my $bytes_read = $self->{sock}->sysread($tempdata,9 - $datalen,length($tempdata));
if (!defined($bytes_read)) {
print_message(LOGLEVEL_TRACE,"SYSREAD FAILED: $!",LOG_TAG);
...abort...
}
if (!$bytes_read) {
if (length($tempdata)) {
print_message(LOGLEVEL_TRACE,"SYSREAD FAILED: Premature EOF",LOG_TAG);
...abort...
}
# Reached EOF without reading anything.
last;
}
}
在您执行这些更改之前,我们不知道您是否遇到错误,更不用说错误了。
评论:
-
您错过了
sysread
的最后一个论点,这在这里是必需的。 -
如果没有超时(因为只有一个句柄),那么像上面那样使用
select
完全没有用。sysread
已经执行了必要的等待。 -
如果有超时,则不是绝对超时。例如,假设您的超时时间为5秒,但您始终每4秒获得1个字节,则上述内容将持续36秒而不会超时。 (好吧,这不是一个现实的例子,只是因为我们只读取9个字节。)对于绝对超时,您需要跟踪时间的流逝。 (我会先使用
my $wait_til = time() + timeout();
,然后在检查其是否为肯定值之前将$wait_til - time()
传递给can_read
。)