返回顶部
首页 > 资讯 > 后端开发 > GO >Go语言实现ssh&scp的方法详解
  • 968
分享到

Go语言实现ssh&scp的方法详解

2024-04-02 19:04:59 968人浏览 薄情痞子
摘要

目录前言连接远程服务器并执行命令(ssh)拷贝远程服务器文件到本地(scp)简单封装下前言 最近遇到一个临时需求,需要将客户环境中一个服务每天的日志进行一系列复杂处理,并生成数据报表

前言

最近遇到一个临时需求,需要将客户环境中一个服务每天的日志进行一系列复杂处理,并生成数据报表。由于数据处理逻辑复杂,且需要存入数据库,在客户环境使用 shell 脚本无法处理,因此就需要将日志先拷贝到本地,再进行处理;同时为了避免每天人工拷贝日志,需要实现自动化,整条链路自动执行,无需人工干预。平时使用 Go 语言较多,由此就引出了 Go 语言 ssh 连接远程客户服务器,并利用 scp 将数据拷贝下来的一系列操作。

说明:本文中的示例,均是基于Go1.17 64位机器

连接远程服务器并执行命令(ssh)

如下给出了使用 用户名+密码 的方式连接远程服务器并执行了 /usr/bin/whoami 命令的示例,步骤如下:

  • 生成 ClientConfig:想要连接远程服务器,必须要至少指定一种实现了 Auth 的 AuthMethod,我们这里使用密码的方式;同时需要提供 一种用于安全校验远程服务端key的方法 HosTKEyCallback,我们这里使用的是不校验的方式 ssh.InsecureIgnoreHostKey(),生产情况下建议使用 ssh.FixedHostKey(key PublicKey)
  • 调用 Dial :Dial 方法与远程服务器建立连接,并返回一个 client ;
  • NewSessionNewSession方法开启一个会话,在一个会话内可以通过 Run 方法执行一个命令。
import (
 "bytes"
 "fmt"
 "log"
  
  "golang.org/x/crypto/ssh"
)

func main() {

 var (
  username = "your username"
  passWord = "your password"
  addr     = "ip:22"
 )
 
 config := &ssh.ClientConfig{
  User: username,
  Auth: []ssh.AuthMethod{
   ssh.Password(password),
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
 }
 client, err := ssh.Dial("tcp", addr, config)
 if err != nil {
  log.Fatal("Failed to dial: ", err)
 }
 defer client.Close()

 // 开启一个session,用于执行一个命令
 session, err := client.NewSession()
 if err != nil {
  log.Fatal("Failed to create session: ", err)
 }
 defer session.Close()

 // 执行命令,并将执行的结果写到 b 中
 var b bytes.Buffer
 session.Stdout = &b
  
  // 也可以使用 session.CombinedOutput() 整合输出
 if err := session.Run("/usr/bin/whoami"); err != nil {
  log.Fatal("Failed to run: " + err.Error())
 }
 fmt.Println(b.String())  // root
}

上面的例子,我们在 Run 方法里面传入了一个命令,然后远程服务器会将执行结果返回给我们,如果是复杂操作,通过传入命令的方式就比较麻烦。比如上面提到的需求,需要我从 k8s 容器中拷贝出服务每天的日志,拆解后的步骤为:获取服务的多个 k8s pod 名称,根据当前日期,从多个容器中分别拷贝日志文件,然后整合成一个日志文件。针对复杂操作,我们可以在远程服务器编写一个脚本,然后 Run 方法中传入执行脚本的命令。

简单举个示例,我们在远程服务器编写了一个脚本 test.sh,放在了 /opt 目录下,脚本内容 与 调用方式分别如下:

# 脚本文件
#!/bin/bash
today=$(date +"%Y-%m-%d")
# 将数据写入文件
$(df -h > $today.log)
package main

import (
 "fmt"
 "log"
  
  "golang.org/x/crypto/ssh"
)

func main() {

 var (
  username = "your username"
  password = "your password"
  addr     = "ip:22"
 )

 config := &ssh.ClientConfig{
  User: username,
  Auth: []ssh.AuthMethod{
   ssh.Password(password),
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
 }
 client, err := ssh.Dial("tcp", addr, config)
 if err != nil {
  log.Fatal("Failed to dial: ", err)
 }
 defer client.Close()


 session, err := client.NewSession()
 if err != nil {
  log.Fatal("Failed to create session: ", err)
 }
 defer session.Close()

  // 调用远程服务器脚本脚本
 res, err := session.CombinedOutput("sh /opt/test.sh")
 if err != nil {
  log.Fatal("Failed to run: " + err.Error())
 }
 fmt.Println(string(res))
  
  
}

拷贝远程服务器文件到本地(scp)

拷贝文件步骤比较简单:

  • 建立 ssh client
  • 基于 ssh client 创建 sftp client
  • 打开远程服务器文件并拷贝到本地
package main

import (
 "io"
 "log"
 "os"
 "time"
  
  "GitHub.com/pkg/sftp"
 "golang.org/x/crypto/ssh"
)

func main() {

 var (
  username = "your username"
  password = "your password"
  addr     = "ip:22"
 )

 // 1. 建立 ssh client
 config := &ssh.ClientConfig{
  User: username,
  Auth: []ssh.AuthMethod{
   ssh.Password(password),
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
 }
 client, err := ssh.Dial("tcp", addr, config)
 if err != nil {
  log.Fatal("Failed to dial: ", err)
 }
 defer client.Close()

 // 2. 基于ssh client, 创建 sftp 客户端
 sftpClient, err := sftp.NewClient(client)
 if err != nil {
  log.Fatal("Failed to init sftp client: ", err)
 }
 defer sftpClient.Close()

 // 3. 打开远程服务器文件
 filename := time.Now().FORMat("2006-01-02") + ".log"
 source, err := sftpClient.Open("/opt/" + filename)
 if err != nil {
  log.Fatal("Failed to open remote file: ", err)
 }
 defer source.Close()

 // 4. 创建本地文件
 target, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
 if err != nil {
  log.Fatal("Failed to open local file: ", err)
 }
 defer target.Close()

 // 5. 数据复制
 n, err := io.Copy(target, source)
 if err != nil {
  log.Fatal("Failed to copy file: ", err)
 }
 log.Println("Succeed to copy file: ", n)

}

在 sftp client 中,还有许多方法,例如 WalkReadDirStatMkdir等,针对文件也有 ReadWriteWriteToReadFrom等方法,像操作本地文件系统一样,非常便利。

简单封装下

package main

import (
 "fmt"
 "io"
 "log"
 "os"
 "time"

 "github.com/pkg/sftp"
 "golang.org/x/crypto/ssh"
)

type Cli struct {
 user   string
 pwd    string
 addr   string
 client *ssh.Client
}


func NewCli(user, pwd, addr string) Cli {
 return Cli{
  user: user,
  pwd:  pwd,
  addr: addr,
 }
}

// Connect 连接远程服务器
func (c *Cli) Connect() error {
 config := &ssh.ClientConfig{
  User: c.user,
  Auth: []ssh.AuthMethod{
   ssh.Password(c.pwd),
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
 }
 client, err := ssh.Dial("tcp", c.addr, config)
 if nil != err {
  return fmt.Errorf("connect server error: %w", err)
 }
 c.client = client
 return nil
}

// Run 运行命令
func (c Cli) Run(shell string) (string, error) {
 if c.client == nil {
  if err := c.Connect(); err != nil {
   return "", err
  }
 }

 session, err := c.client.NewSession()
 if err != nil {
  return "", fmt.Errorf("create new session error: %w", err)
 }
 defer session.Close()

 buf, err := session.CombinedOutput(shell)
 return string(buf), err
}

// Scp 复制文件
func (c Cli) Scp(srcFileName, targetFileName string) (int64, error) {
 if c.client == nil {
  if err := c.Connect(); err != nil {
   return 0, err
  }
 }

 sftpClient, err := sftp.NewClient(c.client)
 if err != nil {
  return 0, fmt.Errorf("new sftp client error: %w", err)
 }
 defer sftpClient.Close()

 source, err := sftpClient.Open(srcFileName)
 if err != nil {
  return 0, fmt.Errorf("sftp client open file error: %w", err)
 }
 defer source.Close()

 target, err := os.OpenFile(targetFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
 if err != nil {
  return 0, fmt.Errorf("open local file error: %w", err)
 }
 defer target.Close()

 n, err := io.Copy(target, source)
 if err != nil {
  return 0, fmt.Errorf("copy file error: %w", err)
 }
 return n, nil
}


// 调用测试
func main() {
 var (
  username = "your username"
  password = "your password"
  addr     = "ip:22"
 )

 // 初始化
 client := NewCli(username, password, addr)

 // ssh 并运行脚本
 _, err := client.Run("sh /opt/test.sh")
 if err != nil {
  log.Printf("failed to run shell,err=[%v]\n", err)
  return
 }

 // scp 文件到本地
 filename := time.Now().Format("2006-01-02") + ".log"
 n, err := client.Scp("/opt/"+filename, filename)
 if err != nil {
  log.Printf("failed to scp file,err=[%v]\n", err)
  return
 }
 log.Printf("Succeed to scp file, size=[%d]\n", n)

 // 处理文件并删除本地文件......
}

通过上面的一系列操作,就可以实现了我的需求:

1.编写程序:

  • 连接客户服务器
  • 执行远程服务器的脚本,生成日志文件
  • 拷贝远程服务器的日志文件到本地
  • 处理日志文件
  • 删除本地文件

2.在服务器上启动一个定时任务运行该程序

以上就是Go语言实现ssh&scp的方法详解的详细内容,更多关于Go语言实现ssh scp的资料请关注编程网其它相关文章!

您可能感兴趣的文档:

--结束END--

本文标题: Go语言实现ssh&scp的方法详解

本文链接: https://lsjlt.com/news/121212.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Go语言实现ssh&scp的方法详解
    目录前言连接远程服务器并执行命令(ssh)拷贝远程服务器文件到本地(scp)简单封装下前言 最近遇到一个临时需求,需要将客户环境中一个服务每天的日志进行一系列复杂处理,并生成数据报表...
    99+
    2024-04-02
  • 如何用 Go 语言实现 SCP
    随着数据传输的不断增长,传输大量数据时如何确保数据安全和传输效率变得越来越重要。SCP (Secure Copy Protocol)是一种安全传输文件的协议,与SSH (Secure Shell)一起使用。本文将介绍如何用 Go 语言实现 ...
    99+
    2023-05-14
  • Go语言实现JSON解析的方法详解
    目录1、json序列化2、Json反序列化为结构体对象3、Json反序列化为map类型4、Tag的使用在日常项目中,使用Json格式进行数据封装是比较常见的操作,看一下golang怎...
    99+
    2024-04-02
  • ssh,scp自动登陆的实现方法
    示例:A为本地主机(即用于控制其他主机的机器) ;B为远程主机(即被控制的机器Server), 假如ip为192.168.60.110;A和B的系统都是Linux 在A上运行命令:# ssh-keygen ...
    99+
    2022-06-04
    方法 ssh scp
  • Go语言代码转C语言的实现方法详解
    随着计算机科技的快速发展,编程语言也在不断涌现。其中,Go语言因其简洁、高效和并发性能而备受关注。然而,在某些特定的场景下,我们可能需要将Go语言代码转换为C语言,以提高性能或兼容性。...
    99+
    2024-03-07
    代码实现 转换方法 go到c go语言
  • Go语言实现定时器的方法详解
    目录TimerTiker本文主要介绍了Go语言实现定时器的两个方法,包括一次性定时器(Timer)和周期性定时器(Ticker),一次性定时器:newTimer()创建一个能够往当前...
    99+
    2022-12-20
    Go语言实现定时器 Go语言定时器 Go 定时器
  • Go语言实现运算符重载的方法详解
    目录前言使用实现总结前言 先带来日常的 GScript 更新:新增了可变参数的特性,语法如下: int add(string s, int ...num){ p...
    99+
    2024-04-02
  • Go语言的Channel遍历方法详解
    先来看看基本的定义: channel是Go语言中的一个核心类型,可以把它看成管道。并发核心单元通过它就可以发送或者接收数据进行通讯,这在一定程度上又进一步降低了编程的难度。 c...
    99+
    2022-06-07
    Channel GO 方法 go语言
  • Go语言类方法和对象方法详解
    go语言中,类方法(type)作用于整个结构体类型,用于执行不操作具体实例的操作。对象方法(receiver)绑定到具体实例,用于操作实例数据。实战案例中,类方法用于创建和获取员工信息,...
    99+
    2024-04-03
    方法 go语言
  • Go语言中UTF-8的实现方法
    这篇文章给大家分享的是有关Go语言中UTF-8的实现方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。go适合做什么go是golang的简称,而golang可以做服务器端开发,且golang很适合做日志处理、数据...
    99+
    2023-06-14
  • Go语言中的路由实现方法
    Go语言中的路由实现方法,需要具体代码示例在Web应用程序中,路由通常用于确定客户端发出的请求应由哪个处理程序来处理。在Go语言中,有多种路由实现方法可供选择。下面将介绍其中三种常用的实现方法,并提供相应的代码示例:net/http包的路由...
    99+
    2023-12-17
    Go语言 路由 实现方法
  • Go语言实现JSON解析的神器详解
    目录前言JSON解析实践标准库encoding/json第三方库json-iterator收集到开源项目jinzaigo/xutil中总结前言 php转go是大趋势,越来越多公司的p...
    99+
    2023-01-29
    Go语言解析JSON Go 解析JSON Go语言 JSON
  • Go语言中rune方法使用详解
    Go语言中rune方法如何使用,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 1.byte类型 byt...
    99+
    2023-03-19
    Go语言rune方法 Go语言rune
  • Go语言函数方法调用详解
    标题:Go语言函数方法调用详解 Go语言作为一种快速、简单、高效的编程语言,其函数方法调用是其中一个重要的特性。本文将详细介绍Go语言中函数方法的调用方式,并提供具体的代码示例,帮助读...
    99+
    2024-04-02
  • Go语言中函数的使用方法详解
    目录函数特点函数知识点函数的使用函数定义函数的参数函数的返回值函数的变量作用域函数的递归调用函数的可变参数函数的闭包函数的 defer 语句注意函数特点 函数可以有多个返回值。可以将...
    99+
    2023-05-18
    Go语言函数使用方法 Go语言函数使用 Go语言函数
  • Go语言方法和函数的区别详解
    Go语言是一门现代化的编程语言,具有简洁高效的特点,其方法和函数在编程中起着不可或缺的作用。在Go语言中,方法和函数虽然都用于实现代码逻辑,但它们在使用和定义方式上存在一定的区别。本文...
    99+
    2024-04-02
  • Go语言字符出现次数统计方法详解
    Go语言作为一种快速、高效、并发性良好的编程语言,广泛应用于网络编程、云计算、数据处理等领域。在实际开发中,经常会遇到需要统计字符串中字符出现次数的场景。本文将详细介绍在Go语言中如何...
    99+
    2024-03-13
    go语言 方法解析 字符统计 网络编程
  • GO语言的控制语句详解包括GO语言的指针语法
    GO语言的控制语句 判断结构:if-else 和大多数编程语言一样,if-else的用法基本都一样,直接来一个GO语言的例子 package main import ( "f...
    99+
    2022-12-19
    GO语言的控制语句详解 GO语言指针语法 GO语言switch结构 GO语言for结构
  • C语言实现手写JSON解析的方法详解
    目录什么是JSONJSON支持的数据类型JSON语法规则JSON的解析JSON基本语法编写解析器头文件实现文件什么是JSON JSON(JavaScript Object Notat...
    99+
    2024-04-02
  • Go语言的type func()用法详解
    目录一、前置基础1. go 函数基础2. 函数签名二、Go语言的type func()用法 | type func() 自定义函数类型1. golang通过type定义函数类型一、前...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作