go函数-死机:运行时错误:无效内存地址或零指针取消引用

go函数-死机:运行时错误:无效内存地址或零指针取消引用,go,Go,提前感谢大家的帮助。我在第41、42和58行标记了问题发生的位置。我无法跟踪抛出错误的原因。似乎所有变量都已正确分配。我使用命令: go run file.go“命令”“ip地址” ex.-go run file.go正常运行时间8.8.8.8 错误是: panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1

提前感谢大家的帮助。我在第41、42和58行标记了问题发生的位置。我无法跟踪抛出错误的原因。似乎所有变量都已正确分配。我使用命令:

go run file.go“命令”“ip地址”
ex.-go run file.go正常运行时间8.8.8.8

错误是:

panic: runtime error: invalid memory address or nil pointer dereference  
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x54fb36]

goroutine 20 [running]:
golang.org/x/crypto/ssh.(*Client).NewSession(0x0, 0x3, 0xc42009e310, 0x10)
    /home/user/go/src/golang.org/x/crypto/ssh/client.go:130 +0x26  
main.executeCmd(0x7ffce5f83a51, 0x6, 0x7ffce5f83a58, 0xd, 0x5d3077, 0x2, 0xc42009a820, 0x0, 0x0)  
    /home/user/ssh.go:58 +0x16f  
main.main.func1(0xc4200d2000, 0x7ffce5f83a51, 0x6, 0xc42009a820,   0x7ffce5f83a58, 0xd, 0x5d3077, 0x2)  
    /home/user/ssh.go:42 +0x7a  
created by main.main  
    /home/user/ssh.go:41 +0x41b

主程序包
进口(
“字节”
“fmt”
“io/ioutil”
“日志”
“操作系统”
“时间”
“golang.org/x/crypto/ssh”
)
func main(){
cmd:=os.Args[1]
主机:=os.Args[2:]
结果:=制造(成串,10)
超时:=时间后(10*时间秒)
端口:=“22”
var hostKey ssh.PublicKey
key,err:=ioutil.ReadFile(“/home/user/file.pem”)
如果错误!=零{
log.Fatalf(“无法读取私钥:%v”,错误)
}
签名者,错误:=ssh.ParsePrivateKey(key)
如果错误!=零{
log.Fatalf(“无法分析私钥:%v”,错误)
}
config:=&ssh.ClientConfig{
用户:“ec2用户”,
Auth:[]ssh.AuthMethod{
ssh.PublicKeys(签名者),
},
HostKeyCallback:ssh.FixedHostKey(hostKey),
}
对于u,主机名:=范围主机{
go func(主机名字符串、端口字符串){//第41行

结果正如@JoshuaKolden指出的,您需要检查ssh.Dial产生的错误,如果值不是
nil
,则不要继续。下面是带有错误检查的
executeCmd
函数的一个版本:

func executeCmd(command, hostname string, port string, config *ssh.ClientConfig) (string, error) {
    conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", hostname, port), config)
    if err != nil {
        return "", err
    }
    defer conn.Close()
    session, err := conn.NewSession() //LINE 58
    if err != nil {
        return "", err
    }
    defer session.Close()

    var stdoutBuf bytes.Buffer
    session.Stdout = &stdoutBuf
    if err := session.Run(command); err != nil {
        return "", err
    }

    return fmt.Sprintf("%s -> %s", hostname, stdoutBuf.String()), nil
}
当然,您还需要调整调用
executeCmd
的goroutine以进行错误处理。可能需要将错误消息打印到
os.Stderr
以找出问题所在

您感到恐慌的原因是,您从
ssh.Dial
中出现了一个错误,将变量
conn
的值保留为
nil
。如果您查看
ssh
包,您可以看到它对指针接收器
c
进行方法调用,以
OpenChannel
。通常这不是一个错误采用指针接收器的结构方法存在问题,但在本例中,
OpenChannel
是嵌入在
客户端
struct中的
Conn
接口的方法。当使用nil接收器调用接口方法时,Go会崩溃

编辑:在goroutine中使用此新版本函数的一种可能方式:

go func(hostname string, port string) {  // LINE 41
    result, err := executeCmd(cmd, hostname, port, config) // LINE 42
    if err != nil {
        fmt.Fprintf(os.Stderr, "error running cmd on host %s port %s: %s", hostname, port, err)
        return
    }
    results <- result
}(hostname, port)
go-func(主机名字符串、端口字符串){//第41行
结果,err:=executeCmd(cmd,主机名,端口,配置)//第42行
如果错误!=零{
fmt.Fprintf(os.Stderr,“在主机%s端口%s:%s上运行cmd时出错”,主机名,端口,错误)
返回
}

结果第一步是处理您在第57行忽略的错误。最有可能的
conn
nil
,返回的错误会告诉您原因。此外,您从未为
hostKey
变量赋值,因此这也会咬到您,尽管会导致错误而不是恐慌。如果您希望隐式信任所有主机,使用
unsecureIgnoreHostKey
而不是
FixedHostKey
。感谢您的帮助。我将goroutine修改为err,results:=我已用如何使用它的示例更新了答案
go func(hostname string, port string) {  // LINE 41
    result, err := executeCmd(cmd, hostname, port, config) // LINE 42
    if err != nil {
        fmt.Fprintf(os.Stderr, "error running cmd on host %s port %s: %s", hostname, port, err)
        return
    }
    results <- result
}(hostname, port)