使用 Windows、IPC::Open3 和 IO::Socket->socketpair() 时,Perl 选择在 sysread 上返回 undef [英] Perl select returning undef on sysread when using Windows, IPC::Open3, and IO::Socket->socketpair()

查看:45
本文介绍了使用 Windows、IPC::Open3 和 IO::Socket->socketpair() 时,Perl 选择在 sysread 上返回 undef的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现了这个例子(@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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆