Golang sftp 实现,并发拷贝文件

老王知识加油站 · · 2840 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

本人通过ssh公钥、私钥先实现可以通过ssh登录到目标机器

ssh root@10.1.1.1

注意这里是免密登录

然后通过指定公钥的方式,实现golang sftp协议传输文件

package main
//go run ops-sftp.go hosts 10.1.1.1,10.1.1.2 /workspace/test/w.txt /workspace/test/source.txt
import (
    "fmt"
    "ops-client/utils/sshClient"
    "os"
    "strings"
    "sync"
    "time"
)

func main() {
    actionType:=os.Args[1]
    ips:=os.Args[2]
    ip_array:=strings.Split(ips,",")
    writeFile:=os.Args[3]
    sourceFile:=os.Args[4]
    host, _ := os.Hostname()
    privateKeyFile := ""
    if host == "MacOS.local" {
        privateKeyFile = "/Users/my/.ssh/id_rsa"
    } else {
        privateKeyFile = "/home/www/.ssh/id_rsa"
    }
    var wg sync.WaitGroup
    tmpSourceFile:=sourceFile
    for _, ip := range ip_array {
        wg.Add(1)
        if actionType=="hosts" {
            tmpSourceFile=sourceFile+"."+ip
        }
        //ip="10.211.163.81"
        go func(ip, privateKeyFile,writeFile,tmpSourceFile string) {
            defer wg.Add(-1)
            err := sshClient.Sftp(ip, privateKeyFile,writeFile,tmpSourceFile)
            if err!=nil {
                time.Sleep(2 * time.Second)
                err := sshClient.Sftp(ip, privateKeyFile,writeFile,tmpSourceFile)
                if err!=nil {
                    fmt.Println(ip,"\t",err)
                    os.Exit(1)
                }
            }
        }(ip, privateKeyFile,writeFile,tmpSourceFile)
        time.Sleep(10 * time.Millisecond)
    }
    wg.Wait()
}

自定义 sshClient 包,新建文件 common.go

package sshClient

import (
   "bytes"
   "golang.org/x/crypto/ssh"
   "io"
   "io/ioutil"
   "log"
   "os"
   "time"
   "github.com/pkg/sftp"
)

func CollectTest(ip string,privateKeyFile string) bool {
   remoteIP := ip+":22"
   user := "root"
   privateKeyBytes, err := ioutil.ReadFile(privateKeyFile)
   if err != nil {
       log.Fatal(err)
   }
   //privateKeyBytes:=[]byte(privateKeyString)
   key, err := ssh.ParsePrivateKey(privateKeyBytes)
   if err != nil {
       log.Fatal(err)
   }

   config := &ssh.ClientConfig{
       User: user,
       Auth: []ssh.AuthMethod{
           // Use the PublicKeys method for remote authentication.
           ssh.PublicKeys(key),
       },
       // using InsecureIgnoreHostKey() for testing purposes
       HostKeyCallback: ssh.InsecureIgnoreHostKey(),
       Timeout:1 * time.Second,
   }

   client, err := ssh.Dial("tcp", remoteIP, config)
   if err != nil {
       //log.Fatalf("unable to connect: %v", err)
       return false
   }
   defer client.Close()

   return true
}

func RunCommand(ip string,privateKeyFile string,cmdString string) (string,string,error) {
   remoteIP := ip+":22"
   user := "root"
   privateKeyBytes, err := ioutil.ReadFile(privateKeyFile)
   if err != nil {
       log.Fatal(err)
   }
   key, err := ssh.ParsePrivateKey(privateKeyBytes)
   if err != nil {
       log.Fatal(err)
   }
   config := &ssh.ClientConfig{
       User: user,
       Auth: []ssh.AuthMethod{
           ssh.PublicKeys(key),
       },
       HostKeyCallback: ssh.InsecureIgnoreHostKey(),
       Timeout:1 * time.Second,
   }

   client, err := ssh.Dial("tcp", remoteIP, config)
   if err != nil {
       //log.Fatalf("unable to connect: %v", err)
       return "","",err
   }
   defer client.Close()

   var stdOut, stdErr bytes.Buffer
   // create session
   session, err := client.NewSession();
   defer session.Close()

   if  err != nil {
       return "","",err
   }
   session.Stdout = &stdOut
   session.Stderr = &stdErr
   err=session.Run(cmdString)
   return stdOut.String(),stdErr.String(),err
}

func Sftp(ip,privateKeyFile,writeFile,sourceFile string) (error) {
   remoteIP := ip+":22"
   user := "root"
   privateKeyBytes, err := ioutil.ReadFile(privateKeyFile)
   if err != nil {
       log.Fatal(err)
   }
   key, err := ssh.ParsePrivateKey(privateKeyBytes)
   if err != nil {
       log.Fatal(err)
   }
   config := &ssh.ClientConfig{
       User: user,
       Auth: []ssh.AuthMethod{
           ssh.PublicKeys(key),
       },
       HostKeyCallback: ssh.InsecureIgnoreHostKey(),
       Timeout:1 * time.Second,
   }

   client, err := ssh.Dial("tcp", remoteIP, config)
   if err != nil {
       return err
   }
   defer client.Close()

   c, err := sftp.NewClient(client)
   if err != nil {
       log.Fatalf("unable to start sftp subsytem: %v", err)
   }
   defer c.Close()

   w, err := c.OpenFile(writeFile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE)
   if err != nil {
       return err
   }
   defer w.Close()

   f, err := os.Open(sourceFile)
   if err != nil {
       return err
   }
   defer f.Close()

   t1 := time.Now()
   n, err := io.Copy(w, f)
   if err != nil {
       return err
   }

   log.Printf("wrote %v bytes in %s", n, time.Since(t1))
   return nil
}

用法

go run ops-sftp.go hosts 10.1.1.1,10.1.1.2 /workspace/test/w.txt /workspace/test/source.txt

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:老王知识加油站

查看原文:Golang sftp 实现,并发拷贝文件

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2840 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传