Golang SSH Terminal终端交互

在使用Golang实现SSH终端交互时,如何正确处理标准输入输出的实时交互?我尝试用os/exec和golang.org/x/crypto/ssh包,但遇到以下问题:

  1. 执行长耗时命令时输出会卡顿
  2. 无法正确捕获Ctrl+C等终端信号
  3. 终端窗口大小变化时格式错乱 有什么成熟的解决方案或最佳实践吗?特别需要支持交互式命令如vim或top的情况。
2 回复

在Golang中实现SSH终端交互,可以使用golang.org/x/crypto/ssh包。基本步骤:

  1. 建立SSH连接:
config := &ssh.ClientConfig{
    User: "username",
    Auth: []ssh.AuthMethod{
        ssh.Password("password"),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", "host:22", config)
  1. 创建会话:
session, err := client.NewSession()
defer session.Close()
  1. 设置终端模式:
modes := ssh.TerminalModes{
    ssh.ECHO:          1,
    ssh.TTY_OP_ISPEED: 14400,
    ssh.TTY_OP_OSPEED: 14400,
}
  1. 请求伪终端并启动shell:
err = session.RequestPty("xterm", 80, 40, modes)
err = session.Shell()
  1. 处理输入输出:
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
  1. 等待会话结束:
err = session.Wait()

注意处理错误和资源释放。对于交互式场景,可能需要处理信号和窗口大小变化。

更多关于Golang SSH Terminal终端交互的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中实现SSH终端交互,你可以使用golang.org/x/crypto/ssh包来建立SSH连接并执行交互式会话。以下是关键步骤和示例代码:

1. 建立SSH连接

package main

import (
    "golang.org/x/crypto/ssh"
    "log"
    "os"
)

func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    client, err := ssh.Dial("tcp", "host:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
    defer client.Close()
}

2. 创建交互式会话

session, err := client.NewSession()
if err != nil {
    log.Fatal("Failed to create session: ", err)
}
defer session.Close()

// 设置终端模式
modes := ssh.TerminalModes{
    ssh.ECHO:          1,     // 启用回显
    ssh.TTY_OP_ISPEED: 14400, // 输入速度
    ssh.TTY_OP_OSPEED: 14400, // 输出速度
}

// 请求伪终端
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
    log.Fatal("Request for pseudo terminal failed: ", err)
}

3. 处理标准输入输出

// 将本地标准输入/输出/错误连接到远程会话
session.Stdin = os.Stdin
session.Stdout = os.Stdout
session.Stderr = os.Stderr

// 启动远程shell
if err := session.Shell(); err != nil {
    log.Fatal("Failed to start shell: ", err)
}

// 等待会话结束
if err := session.Wait(); err != nil {
    log.Fatal("Session failed: ", err)
}

完整示例

package main

import (
    "golang.org/x/crypto/ssh"
    "log"
    "os"
)

func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    client, err := ssh.Dial("tcp", "host:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
    defer client.Close()

    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()

    modes := ssh.TerminalModes{
        ssh.ECHO:          1,
        ssh.TTY_OP_ISPEED: 14400,
        ssh.TTY_OP_OSPEED: 14400,
    }

    if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
        log.Fatal("Request for pseudo terminal failed: ", err)
    }

    session.Stdin = os.Stdin
    session.Stdout = os.Stdout
    session.Stderr = os.Stderr

    if err := session.Shell(); err != nil {
        log.Fatal("Failed to start shell: ", err)
    }

    if err := session.Wait(); err != nil {
        log.Fatal("Session failed: ", err)
    }
}

注意事项:

  1. 安全性:示例中使用InsecureIgnoreHostKey,生产环境应验证主机密钥
  2. 认证方式:支持密码、密钥等多种认证方式
  3. 终端配置:可根据需要调整终端类型和尺寸
  4. 错误处理:需要完善的错误处理机制

这个实现提供了基本的SSH终端交互功能,可以执行命令并保持交互式会话。

回到顶部