目的

Golang中可以使用 golang.org/x/crypto/ssh 包作为SSH客户端或者SSH服务使用。这篇文章将简单记录下作为客户端使用的一些内容。

Package ssh implements an SSH client and server.

基础说明

作为客户端与SSH服务器操作上来说主要分为三步:

ClientClientSessionSession
使用演示

单次通讯

SessionRunOutputCombinedOutput
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())
}
Sessiontop

连续通讯(远程终端)

SessionStartShellWaitShell
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服务器交互还是比较方便的,实际使用中更多的需要注意阻塞方法以及持续执行的外部程序的处理。