栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

关于用golang封装ssh用于在远程主机上执行命令,上传或下载文件

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

关于用golang封装ssh用于在远程主机上执行命令,上传或下载文件

下面由golang教程栏目给大家介绍用golang封装ssh用于在远程主机上执行命令,上传或下载文件,希望对需要的朋友有所帮助!

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封装ssh用于在远程主机上执行命令,上传或下载文件的详细内容,更多请关注考高分网其它相关文章!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/793834.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号