perl - 防止 "mux_client_request_session: read from master failed: Broken pipe"ssh 错误的最佳方法

标签 perl ssh-tunnel

我有一个 perl 脚本,它创建一个 ssh 隧道并在它上面建立一个 Perl DBI 连接来查询远程主机上的数据库:

1 my $ssh = Net::OpenSSH->new('me@host.com');
2 $pid = $ssh->spawn({ssh_opts => '-L 127.0.0.1:12345:127.0.0.1:3306'}, 'sleep 3');

3 return DBI->connect($dsn, $db_user, $db_pass);

这大约在 80% 到 90% 的时间内有效,但其余时间在尝试连接到数据库时出现此错误:

mux_client_request_session: read from master failed: Broken pipe



在解决这个问题的过程中,我注意到我是否在第 2 行之后用 usleep (10000) 短暂地休眠了程序。 ,它 100% 的时间都有效。我不确定这是为什么,但我很好奇知道以及如何正确解决问题。

谢谢。

最佳答案

您的代码中存在竞争条件:spawn运行 ssh在后台启动隧道的命令,有时该命令比 DBI 快 connect启动 TCP 套接字,有时不是,所以 connect失败。

无论如何,我通常推荐的创建隧道的方式是使用控制命令:

 $ssh->system({ssh_opts => [-O => 'forward', '-L3066:localhost:3066']})

如果您想在与数据库的连接建立后移除隧道:
 $ssh->system({ssh_opts => [-O => 'cancel', '-L3066:localhost:3066']});

另外,请注意您必须保留 Net::OpenSSH只要您想使用数据库连接,对象就活着。

总之:
sub dbi_connect {
    my $mysql_port = 3066;
    my $local_port = 12345;
    my $dsn = "DBI:mysql:database=$database;host=localhost;port=$local_port";
    my $tunnel = join ':', $local_port, 'localhost', $mysql_port;
    my $ssh = Net::OpenSSH->new($host, ...);
    $ssh->system({ssh_opts => [-O => 'forward', "-L$tunnel"]});
    my $dbi = DBI->connect($dsn, $db_user, $db_pass);
    $ssh->system({ssh_opts => [-O => 'cancel', "-L$tunnel"]});
    return ($dbi, $ssh);
}

另见 this post在 PerlMonks。

关于perl - 防止 "mux_client_request_session: read from master failed: Broken pipe"ssh 错误的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43960119/

相关文章:

xml - 为什么 XML::Twig 输出提取的字符串两次?

perl - 为什么调用这个函数会改变我的数组?

php - 从 php 执行 bash 脚本并即时输出回网页

ssh - 如何使用私钥分别为 : scp over Jumphost,

python - 当数据库只能通过jumphost访问时如何通过Python连接MySQL

linux - 移动文件的脚本在 Perl 中不起作用

regex - Perl拆分奇怪的行为

javascript - 通过 SSH 隧道访问端点

ssh - 使用 ssh 端口转发运行 Erlang Observer

amazon-web-services - 无法设置到私有(private) AWS API 网关 API 的 SSH 隧道