最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang實現(xiàn)SSH、SFTP操作小結(jié)

 更新時間:2024年04月02日 11:23:31   作者:畱?  
在日常的一些開發(fā)場景中,我們需要去和遠程服務(wù)器進行一些通信,本文主要介紹了Golang實現(xiàn)SSH、SFTP操作小結(jié),具有一定的參考價值,感興趣的可以了解一下

1 前言

在日常的一些開發(fā)場景中,我們需要去和遠程服務(wù)器進行一些通信,執(zhí)行一些相關(guān)命令操作,這個時候我們就可以使用SSH協(xié)議實現(xiàn)目標。SSH協(xié)議是建立在應(yīng)用層上的安全協(xié)議,全稱為Secure Shell,采用的是面向連接的TCP協(xié)議進行傳輸,也就意味著它是安全可靠的。需要注意的是文件傳輸并不能在SSH協(xié)議上完成,需要在下面提到的SFTP協(xié)議完成。

2 Go實現(xiàn)

Go官方為我們提供了用于實現(xiàn)SSH連接的package,位于golang.org/x/crypto下,通過在程序中調(diào)用包中提供的相關(guān)方法,便可以實現(xiàn)與其他機器進行通信。使用前我們需要使用go get導入相關(guān)的依賴包。

go get golang.org/x/crypto/ssh

2.1 配置相關(guān)參數(shù)

在進行通信之前,我們還需要配置一些用于配置一些用于建立連接的相關(guān)參數(shù)。ssh包下的ClientConfig結(jié)構(gòu)體中,定義了建立SSH連接需要用到的一些配置項,部分項提供了默認參數(shù),我們使用時可以不進行聲明。

下面的代碼段中,我們首先是聲明了用戶名和密碼,連接超時時間設(shè)置為10秒鐘,addr變量定義了目標機器的IP地址以及端口。

HostKeyCallback項,我們設(shè)置了忽略,這是因為SSH協(xié)議為客戶端提供了兩種安全驗證方式,一種是基于口令的安全驗證,也就是我們常常使用的賬號密碼形式,另外一種則是基于密鑰的安全驗證,相較于第一種,這種形式的校驗方法極大的提升了安全等級,缺點則是時間損耗相對較長。

如果需要使用這種方式進行校驗,首先我們需要在服務(wù)器上為自己創(chuàng)建一對密鑰,作為客戶端進行訪問時,首先會向服務(wù)端發(fā)送安全驗證請求,服務(wù)端收到請求后,首先會將機器上保存的公鑰與客戶端發(fā)送的公鑰進行比較,如果一致,服務(wù)端則會向客戶端響應(yīng)加密質(zhì)詢,客戶端接受到質(zhì)詢之后,使用私鑰進行解密,然后再將解密結(jié)果發(fā)送給服務(wù)端,服務(wù)端進行校驗后再返回響應(yīng)結(jié)果,到這里就算是完成了一段密鑰校驗。

        //添加配置
        config := &ssh.ClientConfig{
                User: "root",
                Auth: []ssh.AuthMethod{ssh.Password("Password")},
                HostKeyCallback: ssh.InsecureIgnoreHostKey(),
                Timeout: 10 * time.Second,
            }
        }
        addr := fmt.Sprintf("%v:%v", IP, Port)

2.2 建立連接

在完成了所有的參數(shù)初始化之后,我們便可以調(diào)用Dial方法建立SSH連接。Dial方法一共有三個參數(shù)和兩個返回值,第一個參數(shù)network為網(wǎng)絡(luò)類型,這里我們使用面向連接的TCP協(xié)議,第二個參數(shù)addr則為目標機器的IP地址和端口號,第三個參數(shù)config則為前面我們生命的配置項。Dial會返回一個SSH連接和錯誤類型。

func Dial(network, addr string, config *ClientConfig) (*Client, error)

        //建立SSH連接
        sshClient, err := ssh.Dial("tcp", addr, config)
        if err != nil {
            log.Fatal("unable to create ssh conn")
        }

2.3 創(chuàng)建會話

在建立了與目標機器的SSH連接之后,我們就可以通過創(chuàng)建SSH會話來與目標機器進行通信。通過NewSession()方法便可以實現(xiàn)這一操作。

        //建立SSH會話
        sshSession, err := sshClient.NewSession()
        if err != nil {
           log.Fatal("unable to create ssh session")
        }

2.4 執(zhí)行操作

與目標機器建立會話后,我們就可以通過執(zhí)行命令等來操作遠程服務(wù)器。Go目前為我們提供了五個用于操作遠程機器的方法,分別是Run()Start()Output()CombineOutpt()Shell()

??其中 Output(), **CombineOutpt()**這兩個方法是對Run()方法進行不同程度上的封裝,校驗了輸出流,錯誤流等相關(guān)內(nèi)容。

        // Output runs cmd on the remote host and returns its standard output.
        func (s *Session) Output(cmd string) ([]byte, error) {
           if s.Stdout != nil {
              return nil, errors.New("ssh: Stdout already set")
           }
           var b bytes.Buffer
           s.Stdout = &b
           err := s.Run(cmd)
           return b.Bytes(), err
        }
        
        
        // CombinedOutput runs cmd on the remote host and returns its combined
        // standard output and standard error.
        func (s *Session) CombinedOutput(cmd string) ([]byte, error) {
           if s.Stdout != nil {
              return nil, errors.New("ssh: Stdout already set")
           }
           if s.Stderr != nil {
              return nil, errors.New("ssh: Stderr already set")
           }
           var b singleWriter
           s.Stdout = &b
           s.Stderr = &b
           err := s.Run(cmd)
           return b.b.Bytes(), err
        }

Run()方法則是對Start()方法進行了封裝,添加了Wait方法,用于校驗遠程服務(wù)器的退出指令。Wait()方法中有一個管道類型的變量exitStatus,它是用來保存每次執(zhí)行命令后,機器返回的退出狀態(tài)的。有興趣的朋友可以去看看這塊的代碼,這里就不貼代碼了。

這里面有一個坑,如果我們在遠程機器上去運行一個永遠不會停止的程序,這個時候我們的程序一直等待不到遠程機器發(fā)送的退出指令,就會造成程序一直阻塞而無法正常返回。解決的辦法是用一個協(xié)程去單獨執(zhí)行這一塊的任務(wù),或者是使用定時器來定時結(jié)束session會話,來正常返回。

Start()方法與Shell方法一致,都是返回一個error類型,在底層都是調(diào)用了start()方法和SendRequest方法,關(guān)于這兩個方法的內(nèi)容這里就不做詳細介紹了,有興趣的朋友可以自行去閱讀。唯一的區(qū)別是Start()方法有一個string類型的參數(shù),用于接收用戶輸入的參數(shù),而Shell()方法是無參數(shù)的。

使用Shell()方法配合RequestPty()等方法可以在本地建立一個偽終端,可以直接通過輸入命令的形式操作目標機器。下面都會做一個示例。

        //Run
        func (s *Session) Run(cmd string) error {
           err := s.Start(cmd)
           if err != nil {
              fmt.Println(err)
              return err
           }
           return s.Wait()
                }
                
                
        // Start runs cmd on the remote host. Typically, the remote
        // server passes cmd to the shell for interpretation.
        // A Session only accepts one call to Run, Start or Shell.
        func (s *Session) Start(cmd string) error {
           if s.started {
              return errors.New("ssh: session already started")
           }
           req := execMsg{
              Command: cmd,
           }
        
           ok, err := s.ch.SendRequest("exec", true, Marshal(&req))
           if err == nil && !ok {
              err = fmt.Errorf("ssh: command %v failed", cmd)
           }
           if err != nil {
              return err
           }
           return s.start()
        }

2.5 示例代碼(執(zhí)行命令)

這里我們使用Run()方法來演示一下如果去執(zhí)行命令,其他方法類型就不做演示了。這里我們使用一個標準輸出流、錯誤流來保存執(zhí)行結(jié)果。

這里演示了一個簡單的執(zhí)行過程,使用了cd命令到/home/min目錄下,在給helloworld程序添加可執(zhí)行權(quán)限,最后運行程序。

        var stdoutBuf, stderrBuf bytes.Buffer
        session.Stdout = &stdoutBuf
        session.Stderr = &stderrBuf
    
        // cd /home/min
        // chmod +x helloworld
        // ./helloworld
        cmd := fmt.Sprintf("cd %v ; chmod +x %v ; %v &", "/home/min", "helloworld", ./helloworld)
        err := session.Run(cmd)
        if err != nil {
            log.Fatal("[ERROR]: ", session.Stderr, err)
        }

2.6(創(chuàng)建偽終端)

        // 設(shè)置Terminal Mode
	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // 關(guān)閉回顯
		ssh.TTY_OP_ISPEED: 14400, // 設(shè)置傳輸速率
		ssh.TTY_OP_OSPEED: 14400,
	}
    
        // 請求偽終端
	err = session.RequestPty("linux", 32, 160, modes)
	if err != nil {
		log.Println(err)
		return
	}
    
        // 設(shè)置輸入輸出
	session.Stdout = os.Stdout
	session.Stdin = os.Stdin
	session.Stderr = os.Stderr
 
	session.Shell() // 啟動shell
	session.Wait()  // 等待退出

2.7 完整代碼

//機器平臺信息
type Machine struct {
   IP       string
   Port     string
   Username string
   Password string
}

//建立SSH連接
func CreateSSHConn(m *model.Machine) error {
   //初始化連接信息
   config := &ssh.ClientConfig{
      User:            m.Username,
      Auth:            []ssh.AuthMethod{ssh.Password(m.Password)},
      HostKeyCallback: ssh.InsecureIgnoreHostKey(),
      Timeout:         10 * time.Second,
   }
   addr := fmt.Sprintf("%v:%v", m.IP, m.Port)

   //建立ssh連接
   sshClient, err := ssh.Dial("tcp", addr, config)
   if err != nil {
      fmt.Println("unable create ssh conn", err)
      return err
   }
   defer sshClient.Close()
   
   //建立ssh會話
   session, err := sshClient.NewSession()
   if err != nil {
      fmt.Println("unable create ssh conn", err)
      return err
   }
   defer session.Close()
   
   
   //執(zhí)行命令
   var stdoutBuf, stderrBuf bytes.Buffer
   session.Stdout = &stdoutBuf
   session.Stderr = &stderrBuf
   
   cmd := fmt.Sprintf("cd %v ; chmod +x %v ; %v &", "/home/min", "helloworld", ./helloworld)
   if err := session.Run(cmd); err != nil {
       log.Fatal("[ERROR]: ", session.Stderr, err)
   }
  
   //創(chuàng)建偽終端
   // 設(shè)置Terminal Mode
   modes := ssh.TerminalModes{
           ssh.ECHO:          0,     // 關(guān)閉回顯
           ssh.TTY_OP_ISPEED: 14400, // 設(shè)置傳輸速率
           ssh.TTY_OP_OSPEED: 14400,
   }
      
   // 請求偽終端
   err = session.RequestPty("linux", 32, 160, modes)
   if err != nil {
           log.Fatal(err)
   }
      
   // 設(shè)置輸入輸出
   session.Stdout = os.Stdout
   session.Stdin = os.Stdin
   session.Stderr = os.Stderr
   
   session.Shell() // 啟動shell
   session.Wait()  // 等待退出
   
   return err
}

到此這篇關(guān)于Golang實現(xiàn)SSH、SFTP操作小結(jié)的文章就介紹到這了,更多相關(guān)Golang實現(xiàn)SSH和SFT內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • Go語言中定時器cron的基本使用教程

    Go語言中定時器cron的基本使用教程

    這篇文章主要給大家介紹了關(guān)于Go語言中定時器cron使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-01-01
  • 基于Golang設(shè)計一套可控的定時任務(wù)系統(tǒng)

    基于Golang設(shè)計一套可控的定時任務(wù)系統(tǒng)

    這篇文章主要為大家學習介紹了如何基于Golang設(shè)計一套可控的定時任務(wù)系統(tǒng),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-07-07
  • Go進行接口組合的解決方案

    Go進行接口組合的解決方案

    在 Go 語言中,接口組合是一種強大的特性,它允許將多個接口組合成一個新的接口,從而提供更靈活和可擴展的代碼設(shè)計,本文給大家介紹了Go如何進行接口組合,需要的朋友可以參考下
    2024-06-06
  • Go中slog使用入門

    Go中slog使用入門

    slog是Go1.21引入的官方結(jié)構(gòu)化日志庫,本文就來介紹一下Go中slog使用入門,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2026-03-03
  • go語言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等

    go語言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等

    這篇文章主要為大家介紹了go語言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Go使用MongoDB的操作指南(增刪改查)

    Go使用MongoDB的操作指南(增刪改查)

    MongoDB 是一種高性能、開源、文檔型的 NoSQL 數(shù)據(jù)庫,廣泛應(yīng)用于 Web 應(yīng)用、大數(shù)據(jù)以及云計算領(lǐng)域,Go 語言則以其快速、開發(fā)效率高、代碼可維護性強著稱,本指南將詳細介紹如何在 Go 語言中使用 MongoDB 進行數(shù)據(jù)庫操作,需要的朋友可以參考下
    2024-08-08
  • Go語言中io包核心接口示例詳解

    Go語言中io包核心接口示例詳解

    Go的io包提供了io.Reader和io.Writer接口,分別用于數(shù)據(jù)的輸入和輸出,下面這篇文章主要給大家介紹了關(guān)于Go語言中io包核心接口的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • idea搭建go環(huán)境實現(xiàn)go語言開發(fā)

    idea搭建go環(huán)境實現(xiàn)go語言開發(fā)

    這篇文章主要給大家介紹了關(guān)于idea搭建go環(huán)境實現(xiàn)go語言開發(fā)的相關(guān)資料,文中通過圖文介紹以及代碼介紹的非常詳細,對大家學習或者使用go具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-01-01
  • Go 語言遞歸函數(shù)實現(xiàn)方法及應(yīng)用場景

    Go 語言遞歸函數(shù)實現(xiàn)方法及應(yīng)用場景

    遞歸函數(shù)是編程中一種重要的概念,尤其在Go語言中,遞歸被廣泛應(yīng)用于算法設(shè)計和程序開發(fā)中,本文將詳細介紹Go語言中的遞歸函數(shù),包括其基本概念、實現(xiàn)方法以及應(yīng)用場景,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • Gin框架使用panic處理中間件問題詳解

    Gin框架使用panic處理中間件問題詳解

    這篇文章主要介紹了Gin框架使用panic處理中間件問題,在 Gin 框架中,錯誤處理和 panic 處理是非常重要的功能。當處理 HTTP 請求時,可能會出現(xiàn)各種各樣的錯誤,例如數(shù)據(jù)庫連接錯誤、網(wǎng)絡(luò)錯誤、權(quán)限問題等等
    2023-04-04

最新評論

西和县| 云南省| 崇州市| 望城县| 大新县| 手游| 延庆县| 原阳县| 英德市| 尖扎县| 鹤岗市| 靖州| 丁青县| 绵竹市| 平果县| 梓潼县| 兰考县| 苏尼特右旗| 华安县| 扶沟县| 石门县| 奉节县| 监利县| 凤城市| 宁国市| 定陶县| 康定县| 兰西县| 鹤庆县| 贵定县| 利津县| 伊吾县| 西畴县| 淮北市| 江达县| 吴江市| 娄底市| 大兴区| 永泰县| 大新县| 祁连县|