一文带你使用Golang实现SSH客户端

 更新时间:2023年11月09日 09:32:52   作者:路多辛  
SSH 全称为 Secure Shell,是一种用于安全地远程登录到网络上的其他计算机的网络协议,本文主要为大家详细介绍了如何使用 Golang 实现 SSH 客户端,需要的可以参考下

SSH 全称为 Secure Shell,是一种用于安全地远程登录到网络上的其他计算机的网络协议。相信做后端开发的同学没有不了解 SSH的,比较常用的登录服务器的 shell 工具例如 Xshell、SecureCRT、iTerm2 等都是基于 SSH 协议实现的。Golang 中的的 crypto/ssh 包提供了实现 SSH 客户端的功能,本文接下来详细讲解下如何使用 Golang 实现 SSH 客户端。

创建 SSH 客户端配置

首先需要配置一下 SSH 客户端连接服务器的参数,最基本的配置包括用户名、认证方法和主机密钥回调。示例代码如下:

package main
 
import "golang.org/x/crypto/ssh"
 
func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
}

在这个配置中,设置了用户名为"username",密码为"password"。使用 ssh.Password 函数来创建一个密码认证方法。HostKeyCallback 函数会在每次连接到一个新的主机时被调用,用于验证服务器的主机密钥。本例中使用了 ssh.InsecureIgnoreHostKey,意思是接受任何主机密钥。生产环境中不建议这么用,因为不验证主机密钥,存在安全风险。

连接到 SSH 服务器

使用 ssh.Dial 函数可以连接到远程的 SSH 服务器。需要三个参数:网络类型(通常是"tcp"),服务器的地址和端口,以及之前创建的配置对象。示例代码如下:

package main
 
import (
    "golang.org/x/crypto/ssh"
    "log"
)
 
func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
 
    client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
}

连接到 IP 为192.168.3.111服务器的22端口(SSH协议的默认端口),如果连接失败,将返回一个错误,可以使用 log.Fatal 打印错误并退出程序。

创建 SSH 会话

建立了 SSH 连接后就可以创建 SSH 会话了,可以通过会话与服务器进行通信。示例代码如下:

package main
 
import (
    "golang.org/x/crypto/ssh"
    "log"
)
 
func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
 
    client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
 
    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()
}

使用 client.NewSession 方法创建一个新的会话,如果创建失败,将返回一个错误。使用 defer 关键字来确保会话在操作结束后被关闭。

创建伪终端

SSH 协议可以创建伪终端(pseudo terminal),伪终端模拟了一个真实的终端行为,可以运行交互式命令,如 shell 或文本编辑器等。示例代码如下:

package main
 
import (
    "golang.org/x/crypto/ssh"
    "log"
)
 
func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
 
    client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
 
    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()
 
    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
    }
    if err := session.RequestPty("linux", 80, 40, modes); err != nil {
        log.Fatal("request for pseudo terminal failed: ", err)
    }
}

使用 session.RequestPty 方法请求一个伪终端,需要四个参数:终端类型(这里使用"xterm"),终端的宽度和高度,以及一个设置终端模式的 map。在这个 map 中设置了 ssh.ECHO 为0,这将禁止回显,还设置了输入和输出的速度为14.4 kbaud。

设置输入输出

指定远程 shell 的标准输入和输出,示例代码如下:

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", "192.168.3.111:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
 
    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()
 
    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
    }
    if err := session.RequestPty("linux", 80, 40, modes); err != nil {
        log.Fatal("request for pseudo terminal failed: ", err)
    }
 
    //设置输入输出
    session.Stdout = os.Stdout
    session.Stdin = os.Stdin
    session.Stderr = os.Stderr
}

启动远程 shell

一个远程 shell 已经准备就绪了,可以使用 session.Shell 方法启动一个默认的 shell,或者使用 session.Run 方法来运行一个指定的命令。示例代码如下:

package main
 
import (
    "golang.org/x/crypto/ssh"
    "log"
)
 
func main() {
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
 
    client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
 
    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()
 
    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
    }
    if err := session.RequestPty("linux", 80, 40, modes); err != nil {
        log.Fatal("request for pseudo terminal failed: ", err)
    }
  
  //设置输入输出
    session.Stdout = os.Stdout
    session.Stdin = os.Stdin
    session.Stderr = os.Stderr
 
    if err := session.Shell(); err != nil {
        log.Fatal("failed to start shell: ", err)
    }
}

启动了一个默认的 shell,如果启动失败,将返回一个错误。

等待会话结束

使用 session.Wait 方法来阻塞,直到会话结束。示例代码如下:

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", "192.168.3.111:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
 
    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()
 
    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
    }
    if err := session.RequestPty("linux", 80, 40, modes); err != nil {
        log.Fatal("request for pseudo terminal failed: ", err)
    }
 
    //设置输入输出
    session.Stdout = os.Stdout
    session.Stdin = os.Stdin
    session.Stderr = os.Stderr
 
    if err := session.Shell(); err != nil {
        log.Fatal("failed to start shell: ", err)
    }
 
    err = session.Wait()
    if err != nil {
        log.Fatal("Failed to run: " + err.Error())
    }
}

到这里,就完成了一个基本的 SSH 客户端的实现了。这个客户端可以连接到一个 SSH 服务器并启动一个远程 shell,然后等待会话结束。

小结

本文实现的 SSH 客户端只是提供了最基本的功能,要实现一个功能完备、体验良好的 SSH 客户端需要注意很多的细节处理,例如错误处理、重新连接、超时、信号处理等。

以上就是一文带你使用Golang实现SSH客户端的详细内容,更多关于Go实现SSH客户端的资料请关注脚本之家其它相关文章!

相关文章

  • Go语言数据类型详细介绍

    Go语言数据类型详细介绍

    这篇文章主要介绍了Go语言数据类型详细介绍,Go语言数据类型包含基础类型和复合类型两大类,下文关于这两类型的相关介绍,需要的小伙伴可以参考一下
    2022-03-03
  • go语言简单的处理http请求的函数实例

    go语言简单的处理http请求的函数实例

    这篇文章主要介绍了go语言简单的处理http请求的函数,实例分析了Go语言处理http请求的技巧,需要的朋友可以参考下
    2015-03-03
  • Golang交叉编译(跨平台编译)的使用

    Golang交叉编译(跨平台编译)的使用

    本文主要介绍了Golang交叉编译(跨平台编译)的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • golang简单tls协议用法完整示例

    golang简单tls协议用法完整示例

    这篇文章主要介绍了golang简单tls用法,分析了tls协议的使用步骤及客户端与服务器端的相关实现代码,需要的朋友可以参考下
    2016-07-07
  • golang 之 wire 库的使用小结

    golang 之 wire 库的使用小结

    Wire是一个用于Go语言的编译时依赖注入库,通过代码生成提高性能和可维护性,它支持编译时依赖注入、类型安全、简单易用等功能,文章通过代码示例展示了如何使用Wire进行依赖注入,并探讨了其优点如解耦、可测试和维护性,感兴趣的朋友跟随小编一起看看吧
    2025-03-03
  • Go语言七篇入门教程二程序结构与数据类型

    Go语言七篇入门教程二程序结构与数据类型

    这篇文章主要为大家介绍了Go语言的程序结构与数据类型,本篇文章是Go语言七篇入门系列文,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-11-11
  • Golang中的new()和make()函数本质区别

    Golang中的new()和make()函数本质区别

    在 Go 语言开发中,new() 和 make() 是两个容易让开发者感到困惑的内建函数,尽管它们都用于内存分配,但其设计目的、适用场景和底层实现存在本质差异,本文将通过类型系统、内存模型和编译器实现三个维度,深入解析这两个函数的本质区别,感兴趣的朋友一起看看吧
    2025-02-02
  • Go语言官方依赖注入工具Wire的使用教程

    Go语言官方依赖注入工具Wire的使用教程

    依赖注入是一种实现控制反转且用于解决依赖性问题的设计模式。Golang 中常用的依赖注入工具主要有 Inject 、Dig 等。但是今天主要介绍的是 Go 团队开发的 Wire,一个编译期实现依赖注入的工具,感兴趣的可以了解一下
    2022-09-09
  • 详解Golang如何监听某个函数的开始执行和执行结束

    详解Golang如何监听某个函数的开始执行和执行结束

    这篇文章主要为大家详细介绍了Golang如何监听某个函数的开始执行和执行结束,文中的示例代码讲解详细,有需要的小伙伴可以参考一下
    2024-02-02
  • Apache IoTDB开发系统之Go原生接口方法

    Apache IoTDB开发系统之Go原生接口方法

    这篇文章主要为大家介绍了 Apache IoTDB开发系统之Go原生接口方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09

最新评论