我有一个Perl脚本,它使用外部工具(cleartool)来收集有关文件列表的信息.我想使用IPC来避免为每个文件生成一个新进程:
use IPC::Open2;
my ($cin, $cout);
my $child = open2($cout, $cin, 'cleartool');
Run Code Online (Sandbox Code Playgroud)
返回单行的命令运行良好.例如
print $cin "describe -short $file\n";
my $description = <$cout>;
Run Code Online (Sandbox Code Playgroud)
返回多行的命令使我处于死胡同,以便如何使用整个响应而不会被阻塞读取挂起:
print $cin "lshistory $file\n";
# read and process $cout...
Run Code Online (Sandbox Code Playgroud)
我试图通过fcntl以下方式为非阻塞读取设置文件句柄:
use Fcntl;
my $flags = '';
fcntl($cout, F_GETFL, $flags);
$flags |= O_NONBLOCK;
fcntl($cout, F_SETFL, $flags);
Run Code Online (Sandbox Code Playgroud)
但是Fcntl的消息是"你的供应商还没有定义Fcntl宏F_GETFL".
我已经尝试使用IO :: Handle进行设置$cout->blocking(0)但失败了(它返回undef并设置$!为"Unknown error").
select在尝试阅读之前,我曾试图确定是否有可用的数据:
my $rfd = '';
vec($rfd, fileno($cout), 1) = 1;
while (select($rfd, undef, undef, 0) >= 0) {
my $n = read($cout, $buffer, 1024);
print "Read $n bytes\n";
# do something with $buffer...
}
Run Code Online (Sandbox Code Playgroud)
但是没有读过任何东西就挂了.有谁知道如何使这项工作(在Windows上)?
select仅适用于Windows中的套接字.看起来IPC :: OpenX使用普通的文件句柄,因此您将无法使用select它创建的句柄.
如果您不需要select提供的活动的超时/检测,则可以将句柄设置为非阻塞,并按正常方式读取或写入.
如果您需要更细微的控制,IPC :: Run可能会很适合您.
您还可以查看创建socketpair并使用子进程的句柄.较新的perls(5.8及更高版本)支持socketpair使用TCP套接字在Windows上进行仿真.
如果您尝试克隆STDOUT并且STDERR没有控制台运行的程序(即它是以wperl而不是perl启动),您将无法通过STDIO获取数据.
在实践中,这对我来说在几个项目上都是一个巨大的痛苦.我发现最有效的方法是编写子进程以通过TCP连接到父服务器.如果您不控制子进程,请查看IPC::Run或socketpair.