Rumah >pembangunan bahagian belakang >Golang >Satu artikel menerangkan secara terperinci cara golang melaksanakan operasi berkaitan ssh

Satu artikel menerangkan secara terperinci cara golang melaksanakan operasi berkaitan ssh

藏色散人
藏色散人ke hadapan
2022-11-09 16:01:374290semak imbas

Artikel ini diperkenalkan oleh lajur tutorial golang untuk memperkenalkan kepada anda bagaimana golang melaksanakan sambungan SSH dan operasi lain yang berkaitan Saya tertanya-tanya sejauh mana anda tahu tentang SSH? Izinkan saya bercakap dengan anda secara terperinci tentang isu-isu operasi yang berkaitan dengan pelaksanaan ssh oleh Go. Saya harap ia akan membantu rakan-rakan yang memerlukannya.

Satu artikel menerangkan secara terperinci cara golang melaksanakan operasi berkaitan ssh

1.ssh

1.1 Prakata

Dalam beberapa senario pembangunan harian, kita perlu berkomunikasi dengan pelayan jauh Beberapa komunikasi dan pelaksanaan beberapa operasi arahan yang berkaitan Pada masa ini kita boleh menggunakan protokol SSH untuk mencapai matlamat. Protokol SSH ialah protokol keselamatan yang dibina pada lapisan aplikasi Nama penuhnya ialah Secure Shell Ia menggunakan protokol TCP berorientasikan sambungan untuk penghantaran, yang bermaksud ia selamat dan boleh dipercayai. Perlu diingatkan bahawa pemindahan fail tidak boleh diselesaikan pada protokol SSH dan perlu diselesaikan pada protokol SFTP yang dinyatakan di bawah.

1.2 Pelaksanaan Go

Go secara rasmi memberikan kami pakej untuk melaksanakan sambungan SSH, yang terletak di bawah golang.org/x/crypto dan disediakan dengan memanggil pakej dalam program Kaedah berkaitan boleh digunakan untuk berkomunikasi dengan mesin lain. Sebelum digunakan, kita perlu menggunakan go get untuk mengimport pakej pergantungan yang berkaitan.

go get golang.org/x/crypto/ssh

1.2.1 Konfigurasikan parameter berkaitan

Sebelum berkomunikasi, kami juga perlu mengkonfigurasi beberapa parameter berkaitan untuk mewujudkan sambungan. Struktur ClientConfig di bawah pakej ssh mentakrifkan beberapa item konfigurasi yang diperlukan untuk mewujudkan sambungan SSH Sesetengah item menyediakan parameter lalai, yang tidak perlu kami nyatakan apabila menggunakannya.

Dalam coretan kod di bawah, kami mula-mula mengisytiharkan nama pengguna dan kata laluan, menetapkan tamat masa sambungan kepada 10 saat dan pembolehubah addr mentakrifkan alamat IP dan port mesin sasaran. Untuk item

HostKeyCallback, kami menetapkannya untuk mengabaikan Ini kerana protokol SSH menyediakan dua kaedah pengesahan keselamatan untuk pelanggan Satu ialah pengesahan keselamatan berasaskan kata laluan, iaitu borang kata laluan akaun yang sering kami gunakan. Di samping itu, One adalah pengesahan keselamatan berasaskan kunci Berbanding dengan jenis pertama, kaedah pengesahan ini sangat meningkatkan tahap keselamatan.

Jika kita perlu menggunakan kaedah ini untuk pengesahan, mula-mula kita perlu mencipta sepasang kunci untuk diri kita sendiri pada pelayan Apabila mengakses sebagai pelanggan, kami akan menghantar permintaan pengesahan keselamatan terlebih dahulu kepada pelayan, dan pelayan akan menerima Selepas menerima permintaan, ia akan membandingkan kunci awam yang disimpan pada mesin dengan kunci awam yang dihantar oleh pelanggan Jika ia konsisten, pelayan akan bertindak balas kepada pelanggan dengan cabaran yang disulitkan , pelanggan akan menggunakan kunci persendirian untuk menyahsulit Kemudian hasil penyahsulitan dihantar ke pelayan, dan pelayan melakukan pengesahan dan kemudian mengembalikan hasil respons Pada ketika ini, tempoh pengesahan kunci selesai.

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

Selepas melengkapkan semua pemulaan parameter, kita boleh memanggil kaedah Dail untuk mewujudkan sambungan SSH. Kaedah Dail mempunyai sejumlah tiga parameter dan dua nilai pulangan Rangkaian parameter pertama ialah jenis rangkaian Di sini kita menggunakan protokol TCP berorientasikan sambungan parameter ketiga Konfigurasi parameter ialah item konfigurasi kehidupan sebelumnya. Dail akan mengembalikan sambungan SSH dan jenis ralat.

func Dial(rangkaian, rentetan addr, konfigurasi *ClientConfig) (*Pelanggan, ralat)

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

Selepas mewujudkan sambungan dengan mesin sasaran Selepas sambungan SSH, kita boleh berkomunikasi dengan mesin sasaran dengan mencipta sesi SSH. Operasi ini boleh dicapai melalui kaedah NewSession().

        //建立SSH会话
        sshSession, err := sshClient.NewSession()       if err != nil {
           log.Fatal("unable to create ssh session")
        }
1.2.4 Laksanakan operasi

Selepas mewujudkan sesi dengan mesin sasaran, kami boleh mengendalikan pelayan jauh dengan melaksanakan arahan, dsb. Go pada masa ini menyediakan lima kaedah untuk mengendalikan mesin jauh, iaitu

Run(), Start(), Output(), CombineOutpt(), Shell().

? Antaranya,

Output() dan **CombineOutpt()** ialah dua kaedah yang merangkumkan kaedah Run() kepada tahap yang berbeza-beza dan mengesahkan aliran keluaran dan aliran ralat kandungan lain yang berkaitan. Kaedah

        // 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() merangkumi kaedah Start() dan menambah kaedah Tunggu untuk mengesahkan arahan keluar pelayan jauh. Terdapat pembolehubah jenis paip

exitStatus dalam kaedah Wait(), yang digunakan untuk menyimpan status keluar yang dikembalikan oleh mesin selepas setiap pelaksanaan arahan. Rakan-rakan yang berminat boleh melihat kod bahagian ini, tetapi kod itu tidak akan disiarkan di sini.

Terdapat perangkap di sini Jika kita menjalankan program pada mesin jauh yang tidak akan berhenti, dan program kita tidak menunggu arahan keluar yang dihantar oleh mesin jauh, ia akan menyebabkan program disekat. Tidak dapat kembali seperti biasa. Penyelesaiannya adalah dengan menggunakan coroutine untuk melaksanakan tugas ini secara berasingan, atau menggunakan pemasa untuk menamatkan sesi dengan kerap untuk kembali seperti biasa.

Start()方法与Shell方法一致,都是返回一个error类型,在底层都是调用了start()方法和SendRequest方法,关于这两个方法的内容这里就不做详细介绍了,有兴趣的朋友可以自行去阅读。唯一的区别是Start()方法有一个string类型的参数,用于接收用户输入的参数,而Shell()方法是无参数的。

使用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()
        }

1.2.5 示例代码(执行命令)

这里我们使用Run()方法来演示一下如果去执行命令,其他方法类型就不做演示了。这里我们使用一个标准输出流、错误流来保存执行结果。

这里演示了一个简单的执行过程,使用了cd命令到/home/min目录下,在给helloworld程序添加可执行权限,最后运行程序。

        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(创建伪终端)

        // 设置Terminal Mode
	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // 关闭回显
		ssh.TTY_OP_ISPEED: 14400, // 设置传输速率
		ssh.TTY_OP_OSPEED: 14400,
	}    
        // 请求伪终端
	err = session.RequestPty("linux", 32, 160, modes)	if err != nil {
		log.Println(err)		return
	}    
        // 设置输入输出
	session.Stdout = os.Stdout
	session.Stdin = os.Stdin
	session.Stderr = os.Stderr
 
	session.Shell() // 启动shell
	session.Wait()  // 等待退出

1.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()   
   
   //执行命令
   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)
   }  
   //创建伪终端
   // 设置Terminal Mode
   modes := ssh.TerminalModes{
           ssh.ECHO:          0,     // 关闭回显
           ssh.TTY_OP_ISPEED: 14400, // 设置传输速率
           ssh.TTY_OP_OSPEED: 14400,
   }      
   // 请求伪终端
   err = session.RequestPty("linux", 32, 160, modes)   if err != nil {
           log.Fatal(err)
   }      
   // 设置输入输出
   session.Stdout = os.Stdout
   session.Stdin = os.Stdin
   session.Stderr = os.Stderr
   
   session.Shell() // 启动shell
   session.Wait()  // 等待退出
   
   return err
}

Atas ialah kandungan terperinci Satu artikel menerangkan secara terperinci cara golang melaksanakan operasi berkaitan ssh. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.im. Jika ada pelanggaran, sila hubungi admin@php.cn Padam