我正在尝试使用open
模块中的autoflush()
和flush()
方法来清除从IO::Handle
获取的管道句柄,但我认为它不起作用。这是一个例子:
host.pl :
use feature qw(say);
use strict;
use warnings;
my $client_pid = open ( my $fh, '|-', 'client.pl' )
or die "Could not open client: $!";
#$fh->autoflush(1); # adding this line does not help
sleep 2;
say "Host: sent message";
print $fh "Hello";
#print $fh "Hello\n"; # adding a newline works fine
$fh->flush() or warn "$!"; # this does not work
sleep 2;
say "Host exits.";
close $fh;
client.pl :
use feature qw(say);
use strict;
use warnings;
say "Client running..";
chomp (my $line = <STDIN>);
say "Client got line: '$line'";
sleep 1;
say "Client exits..";
运行host.pl
的输出是:
Client running..
Host: sent message
Host exits.
Client got line: 'Hello'
Client exits..
预期输出为:
Client running..
Host: sent message
Client got line: 'Hello'
Client exits..
Host exits.
我知道我可以通过在要打印的字符串末尾添加换行来解决此问题:
print $fh "Hello\n";
但我很好奇为什么$fh->flush()
不能在这里工作?
答案 0 :(得分:3)
数据立即发送到客户端,但客户端等待换行符到达。
readline
(其中<>
是程序中的快捷方式)读取,直到遇到换行符才会返回(虽然更改$/
可以更改该行为。如果您想要调用数据可用后立即返回,请使用sysread
。
use BLOCK_SIZE => 64*1024;
say "Client running..";
while (1) {
my $rv = sysread(\*STDIN, my $buf, BLOCK_SIZE);
die($!) if !defined($rv);
last if !$rv;
say "Got: $buf";
}
请注意,单次打印可能会导致以多个块的形式接收数据。在实践中,尤其是使用套接字而不是管道时,您需要某种方式来构建消息以便可靠地识别它们。例如,以下客户端期望以哨兵终止的消息(哨兵是换行符):
use BLOCK_SIZE => 64*1024;
say "Client running..";
my $buf = '';
while (1) {
my $rv = sysread(\*STDIN, $buf, BLOCK_SIZE, length($buf));
die($!) if !defined($rv);
last if !$rv;
while ($buf =~ s/^([^\n]*)\n//) {
my $msg = $1;
say "Got: $msg";
}
say "Got a partial message" if length($buf);
}
die("Premature EOF\n") if length($buf);
尝试发送:
$fh->autoflush();
print($fh "abc");
sleep(1);
print($fh "def\n");
sleep(1);
print($fh "ghi\njkl\nmno");
sleep(1);
print($fh "pqr\n");
这可以适用于处理长度加前缀的消息或任何其他消息格式。