You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Net::OpenSSH实现Perl与Linux主机的SSH交互式通信问询

Perl通过Net::OpenSSH与远程Python脚本交互的解决方案

问题说明

需要实现Perl脚本借助Net::OpenSSH连接Linux主机,启动远程Python脚本后逐条发送命令,等待响应确认后再发送下一条命令,但现有代码无法完成命令发送与响应读取的交互流程。

解决方案

核心是使用Net::OpenSSH的open2方法创建双向管道,与远程Python脚本的标准输入/输出建立交互通道,替代原有的system调用(system仅能启动进程但无法交互)。

修改后的Perl子程序代码

1. 修正SSH连接子程序的语法错误

原_openSshConnection中master_opts行末尾缺少逗号,导致语法错误,先修正:

use Net::OpenSSH; 
sub _openSshConnection
{   
    my $self = shift;
    my $success = 0;
 
    if (!defined $self->{args}->{ctrlHost} ||
        !defined $self->{args}->{ctrlUser} ||
        !defined $self->{args}->{ctrlPass})
    {   
        $self->_DEBUG("Hostname & User credentials not defined.");  
        $success = 0;
    }
    else
    {
        $self->_DEBUG("Establising SSH connection to %s.", $self->{args}->{ctrlHost});
        my $sshDir = UBX::Utils::getOpenSSHCtlDir();
        my $ssh = Net::OpenSSH->new( $self->{args}->{ctrlHost},
                                    user => $self->{args}->{ctrlUser},
                                    password => $self->{args}->{ctrlPass},
                                    master_opts => [-o => "StrictHostKeyChecking=no", '-X'], # 补全缺失的逗号
                                    ctl_dir => $sshDir,
                                    strict_mode => 0
                                );
        if ($ssh->error) {
            die "Couldn't establish SSH connection: ". $ssh->error;
            $success = 0;
        } else {
            $success = $ssh;
        }       
    }
    $self->_DEBUG("SSH connection:".$success);
    return $success;
}

2. 重写python_Start子程序实现交互逻辑

sub python_Start
{
    my $self = shift;
    my $success = 0;
    my @commands = ('cmd1','cmd2');
    my $remote_py_script = 'python3 /path/script.py';

    # 创建双向管道,获取远程脚本的stdin和stdout句柄
    my ($in, $out) = $self->{ssh}->open2($remote_py_script)
        or die "Failed to start remote Python script: ". $self->{ssh}->error;

    # 设置句柄为非缓冲模式,确保实时交互
    $| = 1;
    select $in; $| = 1;
    select $out; $| = 1;

    foreach my $command (@commands) {
        # 发送命令到远程Python脚本
        print $in "$command\n";
        $self->_DEBUG("Sent command: $command");

        # 读取执行结果和确认响应
        my $output = '';
        my $ack_received = 0;
        while (my $line = <$out>) {
            chomp $line;
            $output .= "$line\n";
            # 检查是否收到确认信号"OK"
            if ($line eq 'OK') {
                $ack_received = 1;
                last;
            }
        }

        if ($ack_received) {
            $self->_DEBUG("Received ACK for command: $command");
            $self->_DEBUG("Command output:\n$output");
        } else {
            $self->_DEBUG("Failed to receive ACK for command: $command");
            last; # 未收到确认则终止循环
        }
    }

    # 发送exit命令关闭远程Python脚本
    print $in "exit\n";
    my $exit_output = <$out>;
    $self->_DEBUG("Remote script exit output: $exit_output");

    # 关闭句柄
    close $in;
    close $out;

    $success = 1;
    return $success;
}

关键说明

  • 双向管道:open2方法创建了连接远程Python脚本的输入输出通道,让Perl可以直接读写远程进程的标准输入输出。
  • 缓冲区设置:将句柄设置为非缓冲模式($| = 1),避免数据滞留缓冲区导致交互延迟。
  • 响应处理:每次发送命令后,循环读取输出直到收到"OK"确认,确保远程脚本已完成当前命令执行。
  • 资源清理:最后发送exit命令关闭远程Python脚本,并关闭管道句柄。

Python脚本兼容性

提供的Python脚本已经正确调用sys.stdout.flush()确保输出实时发送,无需修改即可配合上述Perl代码工作。

内容的提问来源于stack exchange,提问作者lafe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:47:39