使用 Windows、IPC::Open3 和 IO::Socket->socketpair() 时,Perl 选择在 sysread 上返回 undef [英] Perl select returning undef on sysread when using Windows, IPC::Open3, and IO::Socket->socketpair()
问题描述
我发现了这个例子(@ikegami 发布)在使用套接字的 Windows 上使用 IPC::Open3.问题是,当我运行它时,我在 sysread
上收到一个错误一个现有的连接被远程主机强行关闭.该命令运行,select
工作正常,但 sysread
得到一个 undef
而不是预期的 0
文件结束.对于所有命令,此行为并不相同.如果我将命令更改为 echo Hello World!
它不会导致错误.知道这里发生了什么吗?
I found this example (posted by @ikegami) of a way to use IPC::Open3 on windows using sockets. The problem is that, when I run it, I get an error An existing connection was forcibly closed by the remote host on the sysread
. The command runs, the select
works correctly, but the sysread
is getting an undef
instead of the expected 0
for end of file. This behavior is not the same for all commands. If I change the command to echo Hello World!
it does not cause the error. Any idea what is going on here?
这是示例中的代码:
use strict;
use warnings;
use IO::Select qw( );
use IPC::Open3 qw( open3 );
use Socket qw( AF_UNIX SOCK_STREAM PF_UNSPEC );
print( "REMOVE ME: getting started\n" );
sub _pipe {
socketpair($_[0], $_[1], AF_UNIX, SOCK_STREAM, PF_UNSPEC)
or return undef;
shutdown($_[0], 1); # No more writing for reader
shutdown($_[1], 0); # No more reading for writer
return 1;
}
sub _open3 {
local (*TO_CHLD_R, *TO_CHLD_W);
local (*FR_CHLD_R, *FR_CHLD_W);
local (*FR_CHLD_ERR_R, *FR_CHLD_ERR_W);
if ($^O =~ /Win32/) {
_pipe(*TO_CHLD_R, *TO_CHLD_W ) or die $^E;
_pipe(*FR_CHLD_R, *FR_CHLD_W ) or die $^E;
_pipe(*FR_CHLD_ERR_R, *FR_CHLD_ERR_W) or die $^E;
} else {
pipe(*TO_CHLD_R, *TO_CHLD_W ) or die $!;
pipe(*FR_CHLD_R, *FR_CHLD_W ) or die $!;
pipe(*FR_CHLD_ERR_R, *FR_CHLD_ERR_W) or die $!;
}
my $pid = open3('>&TO_CHLD_R', '<&FR_CHLD_W', '<&FR_CHLD_ERR_W', @_);
return ( $pid, *TO_CHLD_W, *FR_CHLD_R, *FR_CHLD_ERR_R );
}
# when i change the command to 'echo Hello World' it works...
my ($pid, $to_chld, $fr_chld, $fr_chld_err) =
_open3('cmd /c "dir /s/b"');
my %objs;
my $in_sel = IO::Select->new();
my $out_sel = IO::Select->new();
for my $fh ($fr_chld, $fr_chld_err) {
my $obj = {
buf => '',
};
$objs{ fileno($fh) } = $obj;
$in_sel->add($fh);
}
close($to_chld);
while ($in_sel->count() + $out_sel->count()) {
my ($ins, $outs) = IO::Select::select($in_sel, $out_sel, undef);
for my $fh (@$ins) {
my $obj = $objs{ fileno($fh) };
our $buf; local *buf = \( $obj->{buf} );
my $bytes_read = sysread($fh, $buf, 64*1024, length($buf));
if (!$bytes_read) {
warn("Error reading from child: $!\n")
if !defined($bytes_read);
$in_sel->remove($fh);
}
}
for my $fh (@$outs) {
}
}
waitpid($pid, 0);
print("STDOUT:\n$objs{ fileno( $fr_chld ) }{buf}");
print("\n" );
print("STDERR:\n$objs{ fileno( $fr_chld_err ) }{buf}");
推荐答案
我认为这是因为使用了诸如 shutdown
之类的东西而不是诸如 close
之类的东西.听起来很安全,可以忽略.
I think it's because something like shutdown
was used instead of something like close
. Sounds safe to ignore.
grep $!{$_}, keys %!
显示ECONNRESET
,所以只需更改
warn("Error reading from child: $!\n")
if !defined($bytes_read);
到
warn("Error reading from child: $!\n")
if !defined($bytes_read) && !$!{ECONNRESET};
这篇关于使用 Windows、IPC::Open3 和 IO::Socket->socketpair() 时,Perl 选择在 sysread 上返回 undef的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!