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

使用Elixir SSHEx框架无法读取网络交换机SSH命令响应问题

问题原因及解决方法

核心原因

  1. SSHEx的cmd!方法不兼容交换机交互式CLI:cmd!设计用于执行后自动退出的命令(如Linux的echo),但网络交换机的CLI执行命令后不会自动关闭通道,而是停在提示符,导致SSHEx一直等待通道关闭信号,最终超时。
  2. 直接调用:ssh时未完整接收消息:交换机的输出会分多段发送,且初始可能附带SCP服务禁用的提示,你之前只接收了一次消息,未获取到show ssh的实际输出。
  3. 算法配置不完全匹配手动SSH:手动连接用的是diffie-hellman-group1-sha1,但SSHEx初始配置仅添加了diffie-hellman-group-exchange-sha1,虽能建立连接,但可能影响后续交互稳定性。

解决方法

方法1:适配SSHEx的交互式shell模式

改用SSHEx.shell进入交互式会话,匹配交换机提示符后发送命令并读取输出:

defmodule FibreTestUi.Ssh do
  defp connect do
    SSHEx.connect(
      ip: '192.168.1.1',
      user: 'admin',
      password: '!Password',
      modify_algorithms: [
        {:append, [{:kex, [:diffie-hellman-group1-sha1, :diffie-hellman-group-exchange-sha1]}]},
        {:append, [{:public_key, [:ssh-rsa, :ssh-dss]}]}
      ]
    )
  end

  def list_port_status do
    {:ok, conn} = connect()
    # 匹配交换机的提示符FS#
    {:ok, shell} = SSHEx.shell(conn, prompt: ~r/FS#/)
    # 发送命令
    SSHEx.send(shell, 'show ssh')
    # 读取直到提示符再次出现
    output = SSHEx.recv(shell, 15000)
    SSHEx.close(shell)
    output
  end
end

方法2:完善:ssh模块的消息接收逻辑

循环接收所有SSH消息,直到通道关闭,确保获取完整输出:

defmodule FibreTestUi.Ssh do
  def send_command do
    {:ok, ssh_pid} =
      :ssh.connect('192.168.1.1', 22,
        user: 'admin',
        save_accepted_host: false,
        silently_accept_hosts: true,
        password: '!Password',
        modify_algorithms: [
          prepend: [kex: [:diffie-hellman-group1-sha1, :diffie-hellman-group-exchange-sha1]],
          prepend: [public_key: [:ssh-rsa, :ssh-dss]]
        ]
      )

    {:ok, chn} = :ssh_connection.session_channel(ssh_pid, 5000)
    :ok = :ssh_connection.exec(ssh_pid, chn, 'show ssh', 5000)
    
    output = receive_all(ssh_pid, chn, [])
    :ssh.close(ssh_pid)
    output
  end

  defp receive_all(ssh_pid, chn, acc) do
    receive do
      {:ssh_cm, ^ssh_pid, {:data, ^chn, _, data}} ->
        receive_all(ssh_pid, chn, [data | acc])
      {:ssh_cm, ^ssh_pid, {:eof, ^chn}} ->
        acc |> Enum.reverse() |> IO.iodata_to_binary()
      {:ssh_cm, ^ssh_pid, {:exit_status, ^chn, _}} ->
        receive_all(ssh_pid, chn, acc)
      {:ssh_cm, ^ssh_pid, {:closed, ^chn}} ->
        acc |> Enum.reverse() |> IO.iodata_to_binary()
    after
      15000 ->
        acc |> Enum.reverse() |> IO.iodata_to_binary()
    end
  end
end

方法3:检查交换机SSH配置

  • 确认交换机允许通过SSH执行exec命令,部分设备默认仅开启交互式shell;
  • 关闭强制SCP的相关配置,避免无关提示干扰命令输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 11:58:09