文章目录
- 目的
- 基础说明
- 使用演示
- 单次通讯
- 连续通讯(远程终端)
- 总结
目的
Golang中可以使用 golang.org/x/crypto/ssh 包作为SSH客户端或者SSH服务使用。这篇文章将简单记录下作为客户端使用的一些内容。
Package ssh implements an SSH client and server.
基础说明
作为客户端与SSH服务器操作上来说主要分为三步:
- 使用一定的参数与SSH服务器建立连接得到
Client
对象; - 在
Client
之上建立会话Session
,设置会话的输入输出等配置; - 通过
Session
进行单次或是连续通讯;
使用演示
单次通讯
Session
的 Run
Output
CombinedOutput
方法都可用于单次通讯,下面是个简单的演示:
package main
import (
"bytes"
"fmt"
"log"
"golang.org/x/crypto/ssh"
)
func main() {
// 设置客户端请求参数
// var hostKey ssh.PublicKey
config := &ssh.ClientConfig{
User: "root",
Auth: []ssh.AuthMethod{
ssh.Password("naisu233"),
},
// HostKeyCallback: ssh.FixedHostKey(hostKey),
HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 忽略主机密钥
}
// 作为客户端连接SSH服务器
client, err := ssh.Dial("tcp", "192.168.31.142: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()
// 设置会话标准输出,运行命令
var b bytes.Buffer
session.Stdout = &b
if err := session.Run("cat /proc/cpuinfo"); err != nil {
log.Fatal("Failed to run: " + err.Error())
}
fmt.Println(b.String())
}
需要注意的是每个 Session
只能进行一次通讯,并且上述的几个方法通讯时会阻塞。另外需要注意的是这几个方法只会在指令运行结束时才会返回结果,不适合用在持续进行的命令中(比如 top
命令)。
连续通讯(远程终端)
连续通讯只要使用 Session
的 Start
Shell
方法,使用这两者时需要使用 Wait
方法来等待结束会话。 Shell
方法可以作为远程终端使用:
package main
import (
"log"
"os"
"golang.org/x/crypto/ssh"
"golang.org/x/term"
)
func main() {
// 设置客户端请求参数
// var hostKey ssh.PublicKey
config := &ssh.ClientConfig{
User: "root",
Auth: []ssh.AuthMethod{
ssh.Password("naisu233"),
},
// HostKeyCallback: ssh.FixedHostKey(hostKey),
HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 忽略主机密钥
}
// 作为客户端连接SSH服务器
conn, err := ssh.Dial("tcp", "192.168.31.142:22", config)
if err != nil {
log.Fatal("unable to connect: ", err)
}
defer conn.Close()
// 创建会话
session, err := conn.NewSession()
if err != nil {
log.Fatal("unable to create session: ", err)
}
defer session.Close()
// 设置会话的标准输出、错误输出、标准输入
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
// 设置终端参数
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
termWidth, termHeight, err := term.GetSize(int(os.Stdout.Fd())) // 获取当前标准输出终端窗口尺寸 // 该操作可能有的平台上不可用,那么下面手动指定终端尺寸即可
if err != nil {
log.Fatal("unable to terminal.GetSize: ", err)
}
// 设置虚拟终端与远程会话关联
if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil {
log.Fatal("request for pseudo terminal failed: ", err)
}
// 启动远程Shell
if err := session.Shell(); err != nil {
log.Fatal("failed to start shell: ", err)
}
// 阻塞直至结束会话
if err := session.Wait(); err != nil {
log.Fatal("exit error: ", err)
}
}
总结
Golang作为客户端与SSH服务器交互还是比较方便的,实际使用中更多的需要注意阻塞方法以及持续执行的外部程序的处理。