欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

golang怎么實(shí)現(xiàn)ssh

這篇文章主要介紹“golang怎么實(shí)現(xiàn)ssh”,在日常操作中,相信很多人在golang怎么實(shí)現(xiàn)ssh問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”golang怎么實(shí)現(xiàn)ssh”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站制作、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的泰寧網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

1.ssh

1.1 前言

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

1.2 Go實(shí)現(xiàn)

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

go get golang.org/x/crypto/ssh

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

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

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

HostKeyCallback項(xiàng),我們?cè)O(shè)置了忽略,這是因?yàn)镾SH協(xié)議為客戶端提供了兩種安全驗(yàn)證方式,一種是基于口令的安全驗(yàn)證,也就是我們常常使用的賬號(hào)密碼形式,另外一種則是基于密鑰的安全驗(yàn)證,相較于第一種,這種形式的校驗(yàn)方法極大的提升了安全等級(jí),缺點(diǎn)則是時(shí)間損耗相對(duì)較長(zhǎng)。

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

        //添加配置
        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)

1.2.2 建立連接

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

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")
        }

1.2.3 創(chuàng)建會(huì)話

在建立了與目標(biāo)機(jī)器的SSH連接之后,我們就可以通過(guò)創(chuàng)建SSH會(huì)話來(lái)與目標(biāo)機(jī)器進(jìn)行通信。通過(guò)NewSession()方法便可以實(shí)現(xiàn)這一操作。

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

1.2.4 執(zhí)行操作

與目標(biāo)機(jī)器建立會(huì)話后,我們就可以通過(guò)執(zhí)行命令等來(lái)操作遠(yuǎn)程服務(wù)器。Go目前為我們提供了五個(gè)用于操作遠(yuǎn)程機(jī)器的方法,分別是Run(), Start(), Output(), CombineOutpt(), Shell()。

?其中 Output(), **CombineOutpt()**這兩個(gè)方法是對(duì)Run()方法進(jìn)行不同程度上的封裝,校驗(yàn)了輸出流,錯(cuò)誤流等相關(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()方法則是對(duì)Start()方法進(jìn)行了封裝,添加了Wait方法,用于校驗(yàn)遠(yuǎn)程服務(wù)器的退出指令。Wait()方法中有一個(gè)管道類型的變量exitStatus,它是用來(lái)保存每次執(zhí)行命令后,機(jī)器返回的退出狀態(tài)的。有興趣的朋友可以去看看這塊的代碼,這里就不貼代碼了。

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

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

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

        //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()
        }

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

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

這里演示了一個(gè)簡(jiǎn)單的執(zhí)行過(guò)程,使用了cd命令到/home/min目錄下,在給helloworld程序添加可執(zhí)行權(quán)限,最后運(yù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)
        }

1.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,
	}    
        // 請(qǐng)求偽終端
	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() // 啟動(dòng)shell
	session.Wait()  // 等待退出

1.2.7 完整代碼

//機(jī)器平臺(tái)信息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會(huì)話
   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,
   }      
   // 請(qǐng)求偽終端
   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() // 啟動(dòng)shell
   session.Wait()  // 等待退出
   
   return err
}

到此,關(guān)于“golang怎么實(shí)現(xiàn)ssh”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

網(wǎng)頁(yè)名稱:golang怎么實(shí)現(xiàn)ssh
地址分享:http://chinadenli.net/article8/pipiip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、響應(yīng)式網(wǎng)站、定制網(wǎng)站、手機(jī)網(wǎng)站建設(shè)、標(biāo)簽優(yōu)化、App設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)