drfqfuhej48511519
drfqfuhej48511519
2018-11-12 05:29

在Go中通过SSH发送文件

已采纳

I found this answer before posting this question but the answer is not clear to me.

Here is the code of the answer:

conn, err := ssh.Dial("tcp", hostname+":22", config)
if err != nil {
    return err
}

session, err := conn.NewSession()
if err != nil {
    return err
}
defer session.Close()

r, err := session.StdoutPipe()
if err != nil {
    return err
}

name := fmt.Sprintf("%s/backup_folder_%v.tar.gz", path, time.Now().Unix())
file, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    return err
}
defer file.Close()

if err := session.Start(cmd); err != nil {
    return err
}

n, err := io.Copy(file, r)
if err != nil {
    return err
}

if err := session.Wait(); err != nil {
    return err
}

return nil

I don't understand relation between the cmd variable and io.Copy, where and how does it know which file to copy. I like the idea of using io.Copy but i do not know how to create the file via ssh and start sending content to it using io.Copy.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dtot74529 dtot74529 3年前

    Here is a minimal example on how to use Go as an scp client:

    config := &ssh.ClientConfig{
        User: "user",
        Auth: []ssh.AuthMethod{
            ssh.Password("pass"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
    
    client, _ := ssh.Dial("tcp", "remotehost:22", config)
    defer client.Close()
    
    session, _ := client.NewSession()
    defer session.Close()
    
    file, _ := os.Open("filetocopy")
    defer file.Close()
    stat, _ := file.Stat()
    
    wg := sync.WaitGroup{}
    wg.Add(1)
    
    go func() {
        hostIn, _ := session.StdinPipe()
        defer hostIn.Close()
        fmt.Fprintf(hostIn, "C0664 %d %s
    ", stat.Size(), "filecopyname")
        io.Copy(hostIn, file)
        fmt.Fprint(hostIn, "\x00")
        wg.Done()
    }()
    
    session.Run("/usr/bin/scp -t /remotedirectory/")
    wg.Wait()
    

    Note that I have ignored all errors only for conciseness.

    1. session.StdinPipe() will create a writable pipe for the remote host.
    2. fmt.Fprintf(... "C0664 ...") will signal the start of a file with 0664 permission, stat.Size() size and the remote filename filecopyname.
    3. io.Copy(hostIn, file) will write the contents of file into hostIn.
    4. fmt.Fprint(hostIn, "\x00") will signal the end of the file.
    5. session.Run("/usr/bin/scp -qt /remotedirectory/") will run the scp command.

    Edit: Added waitgroup per OP's request

    点赞 评论 复制链接分享