首页后端开发其他后端知识如何用golang进行远程访问,上传和下载文件怎样操作

如何用golang进行远程访问,上传和下载文件怎样操作

时间2024-03-27 23:06:03发布访客分类其他后端知识浏览1220
导读:今天就跟大家聊聊有关“如何用golang进行远程访问,上传和下载文件怎样操作”的内容,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 python中可以p...
今天就跟大家聊聊有关“如何用golang进行远程访问,上传和下载文件怎样操作”的内容,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。



python中可以paramiko实现在远程主机上执行命令,上传和下载文件,用go也可以封装一个,在go中用ssh就sftp包可以实现,实现了下面的功能

  • 在远程主机执行命令返回结果、返回值
  • 上传和下载文件远程主机上,以及传输了多少个字节

认证方式

  • 如果指定了密码,那么采用用户+密码的方式认证,否则采用用户+秘钥的方式
    • 如果没有指定用户,则默认使用当前的用户
  • 如果没有指定密码,将采用用户+秘钥方式,默认取~/.ssh/id_rsa文件私钥文件获取秘钥
    和paramik类似

直接上代码

package mainimport (
    "errors"
    "fmt"
    "github.com/pkg/sftp"
    "golang.org/x/crypto/ssh"
    "io"
    "io/ioutil"
    "log"
    "os"
    "os/user"
    "time")var (
    DefaultSShTcpTimeout = 15 * time.Second   // 与ssh建立连接的默认时间,自己设置一个就行)// 错误定义var (
    InvalidHostName = errors.New("invalid parameters: hostname is empty")
    InvalidPort     = errors.New("invalid parameters: port must be range 0 ~ 65535"))// 返回当前用户名func getCurrentUser() string {

    user, _ := user.Current()
    return user.Username}
// 存放上传或下载的信息type TransferInfo struct {

    Kind         string   // upload或download
    Local        string   // 本地路径
    Dst          string   // 目标路径
    TransferByte int64    // 传输的字节数(byte)}
func (t *TransferInfo) String()  string {

    return fmt.Sprintf(`TransforInfo(Kind:"%s", Local: "%s", Dst: "%s", TransferByte: %d)`,
        t.Kind, t.Local, t.Dst, t.TransferByte)}
// 存放执行结果的结构体信息type ExecInfo struct {

    Cmd         string
    Output     []byte
    ExitCode int}
func (e *ExecInfo) OutputString() string {

    return string(e.Output)}
func (e *ExecInfo) String() string {

    return fmt.Sprintf(`ExecInfo(cmd: "%s", exitcode: %d)`,
        e.Cmd, e.ExitCode)}
type AuthConfig struct {

    *ssh.ClientConfig
    User     string
    Password string
    KeyFile  string
    Timeout  time.Duration}
func (a *AuthConfig) setDefault()  {

    if a.User == "" {

        a.User = getCurrentUser()
    }


    if a.KeyFile == "" {

        userHome, _ := os.UserHomeDir()
        a.KeyFile = fmt.Sprintf("%s/.ssh/id_rsa", userHome)
    }


    if a.Timeout == 0 {

        a.Timeout = DefaultSShTcpTimeout    }
}
func (a *AuthConfig) SetAuthMethod() (ssh.AuthMethod, error) {

    a.setDefault()
    if a.Password != "" {

        return ssh.Password(a.Password), nil    }

    data, err := ioutil.ReadFile(a.KeyFile)
    if err != nil {

        return nil, err    }

    singer, err := ssh.ParsePrivateKey(data)
    if err != nil {

        return nil, err    }

    return ssh.PublicKeys(singer), nil}
func (a *AuthConfig) ApplyConfig() error {

    authMethod, err := a.SetAuthMethod()
    if err != nil {

        return err    }
    
    a.ClientConfig = &
ssh.ClientConfig{

        User: a.User,
        Auth: []ssh.AuthMethod{
authMethod}
,
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
        Timeout: a.Timeout,
    }

    return nil}
// 存放连接的结构体type conn struct {

    client     *ssh.Client
    sftpClient *sftp.Client}
func (c *conn) Close()  {

    if c.sftpClient != nil {

        c.sftpClient.Close()
        c.sftpClient = nil    }

    if c.client != nil {

        c.client.Close()
        c.client = nil    }
}
// SSHClient结构体type SSHClient struct {

    conn
    HostName   string
    Port        int
    AuthConfig AuthConfig}
// 设置默认端口信息func (s *SSHClient) setDefaultValue()  {

    if s.Port == 0 {

        s.Port = 22
    }
}
// 与远程主机连接func (s *SSHClient) Connect() error {

    if s.client != nil {

        log.Println("Already Login")
        return nil    }
    
    if err := s.AuthConfig.ApplyConfig();
 err != nil {

        return err    }

    s.setDefaultValue()
    addr := fmt.Sprintf("%s:%d", s.HostName, s.Port)
    var err error
    s.client, err = ssh.Dial("tcp", addr, s.AuthConfig.ClientConfig)
    if err != nil {

        return err    }

    return nil}
// 一个session只能执行一次命令,也就是说不能在同一个session执行多次s.session.CombinedOutput// 如果想执行多次,需要每条为每个命令创建一个session(这里是这样做)func (s *SSHClient) Exec(cmd string) (*ExecInfo, error) {

    session, err := s.client.NewSession()
    if err != nil {

        return nil, err    }

    defer session.Close()
    output, err := session.CombinedOutput(cmd)
    var exitcode int    if err != nil {

        // 断言转成具体实现类型,获取返回值
        exitcode = err.(*ssh.ExitError).ExitStatus()
    }
    
    return &
ExecInfo{

        Cmd: cmd,
        Output: output,
        ExitCode: exitcode,
    }
, nil}
// 将本地文件上传到远程主机上func (s *SSHClient) Upload(localPath string, dstPath string) (*TransferInfo, error) {
    
    transferInfo := &
TransferInfo{
Kind: "upload", Local: localPath, Dst: dstPath, TransferByte: 0}

    var err error    // 如果sftp客户端没有打开,就打开,为了复用
    if s.sftpClient == nil {
    
        if s.sftpClient, err = sftp.NewClient(s.client);
 err != nil {

            return transferInfo, err        }

    }

    localFileObj, err := os.Open(localPath)
    if err != nil {

        return transferInfo, err    }

    defer localFileObj.Close()

    dstFileObj, err := s.sftpClient.Create(dstPath)
    if err != nil {

        return transferInfo, err    }

    defer dstFileObj.Close()

    written, err := io.Copy(dstFileObj, localFileObj)
    if err != nil {

        return transferInfo, err    }

    transferInfo.TransferByte = written    return transferInfo, nil}
// 从远程主机上下载文件到本地func (s *SSHClient) Download(dstPath string, localPath string)  (*TransferInfo, error) {
    
    transferInfo := &
TransferInfo{
Kind: "download", Local: localPath, Dst: dstPath, TransferByte: 0}

    var err error    if s.sftpClient == nil {
    
        if s.sftpClient, err = sftp.NewClient(s.client);
 err != nil {

            return transferInfo, err        }

    }

    //defer s.sftpClient.Close()
    localFileObj, err := os.Create(localPath)
    if err != nil {

        return transferInfo, err    }

    defer localFileObj.Close()

    dstFileObj, err := s.sftpClient.Open(dstPath)
    if err != nil {

        return transferInfo, err    }

    defer dstFileObj.Close()

    written, err := io.Copy(localFileObj, dstFileObj)
    if err != nil {

        return transferInfo, err    }

    transferInfo.TransferByte = written    return transferInfo, nil}
// SSHclient的构造方法func NewSSHClient(hostname string, port int, authConfig AuthConfig) (*SSHClient, error) {

    switch {
    
    case hostname == "":
        return nil, InvalidHostName    case port >
 65535 || port  0:
        return nil, InvalidPort    }
    
    sshClient := &
SSHClient{
HostName: hostname, Port: port, AuthConfig: authConfig}

    err := sshClient.Connect()
    if err != nil {

        return nil, err    }

    return sshClient, nil}
func main()  {
// 测试
    sshClient, err := NewSSHClient("172.16.0.178", 22, AuthConfig{
User: "root"}
)
    if err != nil {

        fmt.Println(err)
        return
    }

    defer sshClient.Close()
    //第一次 执行命令
    execinfo, err := sshClient.Exec("ls -l")
    fmt.Println(execinfo.OutputString(), err)
    //第二次执行命令
    out1, exitcode2 := sshClient.Exec("ifconfig -a")
     fmt.Println(string(out1), exitcode2)
     // 上传文件
    transInfoUpload, err := sshClient.Upload("/tmp/passwd", "/tmp/password_upload")
    fmt.Println(transInfoUpload, err)
    // 下载文件
    transInfoDownload, err := sshClient.Download("/etc/passwd", "/tmp/passwd_download")
    fmt.Println(transInfoDownload, err)}
    



    以上就是关于如何用golang进行远程访问,上传和下载文件怎样操作的介绍啦,需要的朋友可以参考上述内容,希望对大家有帮助,欢迎关注网络,小编将为大家输出更多高质量的实用文章!

    声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

    golang

    若转载请注明出处: 如何用golang进行远程访问,上传和下载文件怎样操作
    本文地址: https://pptw.com/jishu/654538.html
    Viper是什么,应该怎么使用 在golang中string和[]byte分别是什么,它们有什么区别

    游客 回复需填写必要信息