最近公司遇到一個問題,需要拷貝大量圖片到遠(yuǎn)程機(jī)器上去夏跷。
直接上代碼,
// 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,
//這個是問你要不要驗證遠(yuǎn)程主機(jī)拓春,以保證安全性亚隅。這里不驗證
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 連接的 用戶名庶溶,密碼懂鸵,主機(jī)名或IP行疏,SSH端口
sftpClient, err = sftpconnect("user", "passwd", "目的機(jī)器的ip", 目的機(jī)器的端口)
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 連接的 用戶名酿联,密碼,主機(jī)名或IP贞让,SSH端口
sshftpClient := NewSftpClient()
// 用來測試的本地文件路徑 和 遠(yuǎn)程機(jī)器上的文件夾
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 這個方法喳张,此文件應(yīng)該有個全局變量
var sftpClient *sftp.Client
全局變量,保證不會出現(xiàn)tcp關(guān)閉不掉的錯誤摸航,這個惡心的錯誤就是:
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
}