基于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
相关产品推荐
相关产品推荐

