一文帶你使用Golang實現(xiàn)SSH客戶端
SSH 全稱為 Secure Shell,是一種用于安全地遠程登錄到網(wǎng)絡(luò)上的其他計算機的網(wǎng)絡(luò)協(xié)議。相信做后端開發(fā)的同學沒有不了解 SSH的,比較常用的登錄服務(wù)器的 shell 工具例如 Xshell、SecureCRT、iTerm2 等都是基于 SSH 協(xié)議實現(xiàn)的。Golang 中的的 crypto/ssh 包提供了實現(xiàn) SSH 客戶端的功能,本文接下來詳細講解下如何使用 Golang 實現(xiàn) SSH 客戶端。
創(chuàng)建 SSH 客戶端配置
首先需要配置一下 SSH 客戶端連接服務(wù)器的參數(shù),最基本的配置包括用戶名、認證方法和主機密鑰回調(diào)。示例代碼如下:
package main
import "golang.org/x/crypto/ssh"
func main() {
config := &ssh.ClientConfig{
User: "username",
Auth: []ssh.AuthMethod{
ssh.Password("password"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
}
在這個配置中,設(shè)置了用戶名為"username",密碼為"password"。使用 ssh.Password 函數(shù)來創(chuàng)建一個密碼認證方法。HostKeyCallback 函數(shù)會在每次連接到一個新的主機時被調(diào)用,用于驗證服務(wù)器的主機密鑰。本例中使用了 ssh.InsecureIgnoreHostKey,意思是接受任何主機密鑰。生產(chǎn)環(huán)境中不建議這么用,因為不驗證主機密鑰,存在安全風險。
連接到 SSH 服務(wù)器
使用 ssh.Dial 函數(shù)可以連接到遠程的 SSH 服務(wù)器。需要三個參數(shù):網(wǎng)絡(luò)類型(通常是"tcp"),服務(wù)器的地址和端口,以及之前創(chuàng)建的配置對象。示例代碼如下:
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服務(wù)器的22端口(SSH協(xié)議的默認端口),如果連接失敗,將返回一個錯誤,可以使用 log.Fatal 打印錯誤并退出程序。
創(chuàng)建 SSH 會話
建立了 SSH 連接后就可以創(chuàng)建 SSH 會話了,可以通過會話與服務(wù)器進行通信。示例代碼如下:
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 方法創(chuàng)建一個新的會話,如果創(chuàng)建失敗,將返回一個錯誤。使用 defer 關(guān)鍵字來確保會話在操作結(jié)束后被關(guān)閉。
創(chuàng)建偽終端
SSH 協(xié)議可以創(chuàng)建偽終端(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 方法請求一個偽終端,需要四個參數(shù):終端類型(這里使用"xterm"),終端的寬度和高度,以及一個設(shè)置終端模式的 map。在這個 map 中設(shè)置了 ssh.ECHO 為0,這將禁止回顯,還設(shè)置了輸入和輸出的速度為14.4 kbaud。
設(shè)置輸入輸出
指定遠程 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)
}
//設(shè)置輸入輸出
session.Stdout = os.Stdout
session.Stdin = os.Stdin
session.Stderr = os.Stderr
}啟動遠程 shell
一個遠程 shell 已經(jīng)準備就緒了,可以使用 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)
}
//設(shè)置輸入輸出
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,如果啟動失敗,將返回一個錯誤。
等待會話結(jié)束
使用 session.Wait 方法來阻塞,直到會話結(jié)束。示例代碼如下:
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)
}
//設(shè)置輸入輸出
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 客戶端的實現(xiàn)了。這個客戶端可以連接到一個 SSH 服務(wù)器并啟動一個遠程 shell,然后等待會話結(jié)束。
小結(jié)
本文實現(xiàn)的 SSH 客戶端只是提供了最基本的功能,要實現(xiàn)一個功能完備、體驗良好的 SSH 客戶端需要注意很多的細節(jié)處理,例如錯誤處理、重新連接、超時、信號處理等。
以上就是一文帶你使用Golang實現(xiàn)SSH客戶端的詳細內(nèi)容,更多關(guān)于Go實現(xiàn)SSH客戶端的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語言七篇入門教程二程序結(jié)構(gòu)與數(shù)據(jù)類型
這篇文章主要為大家介紹了Go語言的程序結(jié)構(gòu)與數(shù)據(jù)類型,本篇文章是Go語言七篇入門系列文,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-11-11
Golang中的new()和make()函數(shù)本質(zhì)區(qū)別
在 Go 語言開發(fā)中,new() 和 make() 是兩個容易讓開發(fā)者感到困惑的內(nèi)建函數(shù),盡管它們都用于內(nèi)存分配,但其設(shè)計目的、適用場景和底層實現(xiàn)存在本質(zhì)差異,本文將通過類型系統(tǒng)、內(nèi)存模型和編譯器實現(xiàn)三個維度,深入解析這兩個函數(shù)的本質(zhì)區(qū)別,感興趣的朋友一起看看吧2025-02-02
詳解Golang如何監(jiān)聽某個函數(shù)的開始執(zhí)行和執(zhí)行結(jié)束
這篇文章主要為大家詳細介紹了Golang如何監(jiān)聽某個函數(shù)的開始執(zhí)行和執(zhí)行結(jié)束,文中的示例代碼講解詳細,有需要的小伙伴可以參考一下2024-02-02
Apache?IoTDB開發(fā)系統(tǒng)之Go原生接口方法
這篇文章主要為大家介紹了?Apache?IoTDB開發(fā)系統(tǒng)之Go原生接口方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09

