以下代码应该从套接字中读取一些未确定的行数。
use warnings;
use strict;
use IO::Socket::INET;
my $server = shift;
my $port = shift;
my $sock = new IO::Socket::INET (
PeerAddr => $server,
PeerPort => $port,
Proto => 'tcp',
Timeout => 1,
Blocking => 0
)
or die "Could not connect";
while (my $in = <$sock>) {
print "$in";
}
print "Received last line\n";
不幸的是,尽管我设置了$in = <$sock>
并且服务器不再发送任何文本,但Blocking => 0
部分仍在阻止。因此,Received last line
不会被打印出来。
所以,我尝试用use IO::Select
来改善行为:
use warnings;
use strict;
use IO::Socket::INET;
use IO::Select;
my $server = shift;
my $port = shift;
my $sock = new IO::Socket::INET (
PeerAddr => $server,
PeerPort => $port,
Proto => 'tcp',
Timeout => 1,
Blocking => 1
)
or die "Could not connect";
my $select = new IO::Select;
$select -> add($sock);
sleep 1;
while ($select -> can_read) {
my $in = <$sock>;
print $in;
}
第二种方法只打印第一个发送的行,然后似乎永远阻止。
由于我看到这样的例子有效,我认为问题是Windows,我试图运行这些脚本。
有没有办法实现非阻塞读取?
答案 0 :(得分:1)
使用select
(由can_read
使用)时,它无法跟进阻止IO的目的。您还必须避免缓冲IO,因为系统(即select
)不知道库缓冲区中的任何数据。这意味着您无法将select
与read
,readline
(又名<>
和<$fh>
)和eof
混合在一起。您必须使用sysread
。
my %clients;
for my $fh ($select->can_read()) {
my $client = $clients{$fh} //= {};
our $buf; local *buf = $client->{buf} //= ''; # alias my $buf = $client->{buf};
my $rv = sysread($sock, $buf, 64*1024, length($buf));
if (!defined($rv)) {
my $error = $!;
$select->remove($fh);
delete($clients{$fh});
# ... Handle error ...
next;
}
if (!$rv) {
$select->remove($fh);
delete($clients{$fh});
# ... Handle EOF ... # Don't forget to check if there's anything in $buf.
next;
}
... remove any complete messages from $buf and handle them ...
}
如果您想一次阅读一行,请使用
while ($buf =~ s/^([^\n]*)\n//) {
process_msg($client, $1);
}