Golang - 到多个节点的并发 SSH 连接

Geo*_* K. 5 ssh concurrency channel go

我有一组服务器,我正在尝试与其建立 SSH 连接,并且我正在为我必须建立的每个新 SSH 连接生成一个新的 goroutine。然后我将连接的结果(连同错误(如果有))发送到一个通道,然后从通道中读取。这个程序有点工作,但即使我关闭了频道,它最终还是冻结了。

这是我到目前为止:

package main

import (
    "fmt"
    "net"
    "sync"

    "github.com/awslabs/aws-sdk-go/aws"
    "github.com/awslabs/aws-sdk-go/service/ec2"
)

// ConnectionResult container
type ConnectionResult struct {
    host    string
    message string
}

func main() {
    cnres := make(chan ConnectionResult)
    ec2svc := ec2.New(&aws.Config{Region: "us-east-1"})
    wg := sync.WaitGroup{}

    params := &ec2.DescribeInstancesInput{
        Filters: []*ec2.Filter{
            &ec2.Filter{
                Name: aws.String("instance-state-name"),
                Values: []*string{
                    aws.String("running"),
                },
            },
        },
    }

    resp, err := ec2svc.DescribeInstances(params)
    if err != nil {
        panic(err)
    }

    for _, res := range resp.Reservations {
        for _, inst := range res.Instances {
            for _, tag := range inst.Tags {
                if *tag.Key == "Name" {
                    host := *tag.Value
                    wg.Add(1)
                    go func(hostname string, cr chan ConnectionResult) {
                        defer wg.Done()
                        _, err := net.Dial("tcp", host+":22")
                        if err != nil {
                            cr <- ConnectionResult{host, "failed"}
                        } else {
                            cr <- ConnectionResult{host, "succeeded"}
                        }
                    }(host, cnres)
                }
            }
        }
    }

    for cr := range cnres {
        fmt.Println("Connection to " + cr.host + " " + cr.message)
    }

    close(cnres)

    defer wg.Wait()
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?有没有更好的方法在 Go 中进行并发 SSH 连接?

Fre*_*rdt 3

上面的代码陷入了循环range cnres for正如优秀的“Go by example”中所指出的,range只会在封闭的通道上退出。

解决这个困难的一种方法是range cnres在另一个 goroutine 中运行迭代。然后您可以wg.Wait(),然后是close()频道,如下所示:

...
go func() {
        for cr := range cnres {
                fmt.Println("Connection to " + cr.host + " " + cr.message)
        }   
}() 
wg.Wait()
close(cnres)
Run Code Online (Sandbox Code Playgroud)

hostname顺便说一句(与被卡住的代码无关),我认为目的是在函数中使用Dial(),以及后续的通道写入,而不是host.