最近公司遇到一个问题,需要拷贝大量图片到远程机器上去。
直接上代码,
// main.go
package main
import (
"fmt"
"log"
"net"
"os"
"path"
"time"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
func sshconnect(user, password, host string, port int) (*ssh.Session, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
client *ssh.Client
session *ssh.Session
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
clientConfig = &ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 30 * time.Second,
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create session
if session, err = client.NewSession(); err != nil {
return nil, err
}
return session, nil
}
func sftpconnect(user, password, host string, port int) (*sftp.Client, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
sshClient *ssh.Client
sftpClient *sftp.Client
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
clientConfig = &ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 30 * time.Second,
//这个是问你要不要验证远程主机,以保证安全性。这里不验证
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if sshClient, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create sftp client
if sftpClient, err = sftp.NewClient(sshClient); err != nil {
return nil, err
}
return sftpClient, nil
}
//单个copy
func scpCopy(localFilePath, remoteDir string) error {
var (
sftpClient *sftp.Client
err error
)
// 这里换成实际的 SSH 连接的 用户名,密码,主机名或IP,SSH端口
sftpClient, err = sftpconnect("user", "passwd", "目的机器的ip", 目的机器的端口)
if err != nil {
log.Println("scpCopy:", err)
return err
}
defer sftpClient.Close()
srcFile, err := os.Open(localFilePath)
if err != nil {
log.Println("scpCopy:", err)
return err
}
defer srcFile.Close()
var remoteFileName = path.Base(localFilePath)
dstFile, err := sftpClient.Create(path.Join(remoteDir, remoteFileName))
if err != nil {
log.Println("scpCopy:", err)
return err
}
defer dstFile.Close()
buf := make([]byte, 1024)
for {
n, _ := srcFile.Read(buf)
if n == 0 {
break
}
dstFile.Write(buf[0:n])
}
return nil
}
这里是批量copy
//批量copy
func scpListCopy(cinfos []CouponInfo) error {
var localFilePath, remoteDir string
// 这里换成实际的 SSH 连接的 用户名,密码,主机名或IP,SSH端口
sshftpClient := NewSftpClient()
// 用来测试的本地文件路径 和 远程机器上的文件夹
for _, v := range cinfos {
for i := 0; i < len(v.Coupons); i++ {
localFilePath = v.Coupons[i].Addr
remoteDir = "目的地址"
srcFile, err := os.Open(localFilePath)
if err != nil {
logger.Println("scpListCopy1:", err)
return err
}
defer srcFile.Close()
var remoteFileName = path.Base(localFilePath)
dstFile, err := sshftpClient.Create(path.Join(remoteDir, remoteFileName))
if err != nil {
logger.Println("scpListCopy2:", err)
return err
}
defer dstFile.Close()
buf := make([]byte, 1024)
for {
n, _ := srcFile.Read(buf)
if n == 0 {
break
}
dstFile.Write(buf[0:n])
}
}
}
return nil
}
/*
NewSftpClient 这个方法,此文件应该有个全局变量
var sftpClient *sftp.Client
全局变量,保证不会出现tcp关闭不掉的错误,这个恶心的错误就是:
ssh: unexpected packet in response to channel open: <nil>
*/
func NewSftpClient() *sftp.Client {
var err error
if sftpClient == nil {
sftpClient, err = sftpconnect("duyq", "duyuqing123456", "10.250.129.22", 22)
if err != nil {
logger.Fatalln("NewSftpClient:", err)
}
}
return sftpClient
}
网友评论