PHP通过Net/SSH2连接华为OLT MA5680T响应缓慢问题排查
初始问题
使用phpseclib的SSH2.php库编写PHP脚本与华为OLT MA5680T通信时,所有远程操作耗时极长(约40秒),即使执行简单命令也无改善。同一库连接其他设备时执行迅速,日志未发现SSH2.php与MA5680T通信存在错误。当前使用的SSH连接函数如下:
function sessione_ssh($olt_id) { global $ssh; global $ip_olt; $ssh = new Net_SSH2($row_olt['olt_ip']); if (!$ssh->login($row_olt['olt_user'], $row_olt['olt_pass'])) { exit('Login Failed'); } $ssh->setWindowColumns(200); $ssh->read('MA5680T>'); $ssh->write("enable\n"); $ssh->read('MA5680T#'); $ssh->write("mmi-mode enable\n"); $ssh->read('MA5680T#'); }
更新后问题
按照建议指定prompt后,主菜单操作耗时降至约3秒,但进入子菜单(如执行$ssh->write("interface gpon " . $frame . "/" . $board . "\n");)时,即使指定对应提示符$ssh->read('MA5680T(config-if-gpon-' . $frame_ont . '/' . $board_ont . ')#');仍出现10秒超时。日志显示提示符前存在异常感叹号:.......!....MA5680T(config-if-gpon-0/13)#
原因分析
华为MA5680T切换子界面(如GPON接口视图)时,会输出链路状态提示或控制台冗余字符(即你看到的感叹号、点),导致$ssh->read()等待精确匹配的提示符时,因为前面的额外字符无法及时匹配,最终触发超时。
解决办法
使用正则表达式匹配提示符
放弃精确字符串匹配,改用正则表达式忽略提示符前的任意字符,示例:// 通用GPON接口提示符匹配 $ssh->read('/MA5680T\(config-if-gpon-\d+\/\d+\)#/');或针对具体框/板号动态生成正则:
$target_prompt = $frame_ont . '/' . $board_ont; $prompt_pattern = '/.*MA5680T\(config-if-gpon-' . preg_quote($target_prompt, '/') . '\)#/'; $ssh->read($prompt_pattern);其中
.*会匹配提示符前所有冗余字符,确保快速定位目标提示符。调整read函数超时参数
结合正则匹配,给read()设置更合理的超时时间,避免不必要的等待:$ssh->read($prompt_pattern, NET_SSH2_READ_REGEX, 5); // 设置5秒超时提前读取缓冲区冗余内容
若设备频繁输出冗余字符,可在执行命令后先读取所有临时输出,再匹配目标提示符:$ssh->write("interface gpon {$frame}/{$board}\n"); // 先清空缓冲区临时输出 $temp_output = $ssh->read(); // 再匹配目标提示符 $ssh->read($prompt_pattern);
额外优化建议
避免使用global变量传递SSH连接,改用函数返回连接对象,提升代码健壮性:
function sessione_ssh($olt_id) { // 假设$row_olt为从数据库获取的设备信息 $ssh = new Net_SSH2($row_olt['olt_ip']); if (!$ssh->login($row_olt['olt_user'], $row_olt['olt_pass'])) { exit('Login Failed'); } $ssh->setWindowColumns(200); $ssh->read('/MA5680T>/'); $ssh->write("enable\n"); $ssh->read('/MA5680T#/'); $ssh->write("mmi-mode enable\n"); $ssh->read('/MA5680T#/'); return $ssh; } // 调用方式 $ssh = sessione_ssh($olt_id);
内容的提问来源于stack exchange,提问作者Sincerbex

