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

基于JSch API逐行在Cisco路由器执行命令的问题排查

问题分析与修复方案

你的代码存在几个关键问题,导致无法正确获取命令执行结果:

  1. 命令未添加触发符:Cisco路由器需要命令后跟随回车(\r\n)才会执行,原代码直接发送命令字符串,设备不会处理。
  2. 输出流未重置:ByteArrayOutputStream在循环中没有清空,每次打印的是所有历史输出的累加结果,而非当前命令的输出。
  3. InputStream使用错误:每次循环替换channel.setInputStream(),会导致流被覆盖,无法保证命令完整发送;且应该使用持续的输入流,而非每次创建新流。
  4. 依赖setOutputStream不可靠:JSch的setOutputStream是将通道输出重定向,但更可靠的方式是主动读取通道的输入流来获取设备输出。

修正后的代码

/**
 * 逐行向路由器下发配置命令并获取执行结果
 * @param configLines
 * @throws DeviceExcpetion
 */
public void deliverConfig(List<String> configLines) throws DeviceExcpetion {
    Channel channel = null;
    JSch jSch = new JSch();
    Session session = null;
    InputStream channelInputStream = null;
    OutputStream channelOutputStream = null;
    BufferedReader reader = null;

    try {
        session = jSch.getSession(userid, ipAddress, port);
        session.setPassword(password);
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect();

        // 打开shell通道
        channel = session.openChannel("shell");
        channelInputStream = channel.getInputStream();
        channelOutputStream = channel.getOutputStream();
        reader = new BufferedReader(new InputStreamReader(channelInputStream, StandardCharsets.UTF_8));

        channel.connect();

        // 先读取初始提示符,确保设备就绪
        waitForPrompt(reader);

        for (String line : configLines) {
            // 发送命令,添加回车符触发执行
            String command = line + "\r\n";
            channelOutputStream.write(command.getBytes(StandardCharsets.UTF_8));
            channelOutputStream.flush();

            // 等待命令执行完成并读取输出
            String response = readUntilPrompt(reader);
            System.out.println("命令[" + line + "]执行结果:\n" + response);
        }

    } catch (JSchException | IOException | InterruptedException e) {
        e.printStackTrace();
        throw new DeviceExcpetion(e.getMessage());
    } finally {
        // 关闭资源
        try {
            if (reader != null) reader.close();
            if (channelInputStream != null) channelInputStream.close();
            if (channelOutputStream != null) channelOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (channel != null) channel.disconnect();
        if (session != null) session.disconnect();
    }
}

/**
 * 等待设备提示符出现(适配Cisco常见提示符如Router>、Router#)
 */
private void waitForPrompt(BufferedReader reader) throws IOException, InterruptedException {
    StringBuilder sb = new StringBuilder();
    while (true) {
        if (reader.ready()) {
            char c = (char) reader.read();
            sb.append(c);
            String content = sb.toString();
            // 判断是否出现提示符,可根据实际设备调整正则
            if (content.matches(".*[>#]$")) {
                break;
            }
        } else {
            Thread.sleep(200);
        }
    }
}

/**
 * 读取输出直到提示符出现,返回命令执行结果(不含提示符)
 */
private String readUntilPrompt(BufferedReader reader) throws IOException, InterruptedException {
    StringBuilder sb = new StringBuilder();
    while (true) {
        if (reader.ready()) {
            char c = (char) reader.read();
            sb.append(c);
            String content = sb.toString();
            // 判断是否出现提示符
            if (content.matches(".*[>#]$")) {
                // 去掉最后的提示符部分
                int promptIndex = content.lastIndexOf(content.charAt(content.length()-1));
                return content.substring(0, promptIndex).trim();
            }
        } else {
            Thread.sleep(200);
        }
    }
}

关键修改说明

  • 添加命令触发符:所有命令后添加\r\n,确保Cisco设备识别并执行命令。
  • 主动读取通道输入流:通过channel.getInputStream()获取设备输出,使用BufferedReader逐字符读取,可靠性更高。
  • 等待提示符机制:通过判断设备提示符(如>或#)确定命令执行完成,替代固定Thread.sleep(),适配不同设备的响应速度。
  • 资源正确关闭:在finally块中关闭所有IO流,避免资源泄漏。
  • 单次输出隔离:每次读取到提示符后返回当前命令的输出,不会累计历史内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:27:48