在 golang 的 ssh 会话关闭时收到 EOF 错误

4
我正在使用 'ssh' 的 Golang 模块,并且想知道我是否已经实现它(或正在尝试实现)。 在 session.Close() 期间是否期望 "EOF" 为错误?在我看到的在线示例中,没有人检查 session.Close() 的错误。我应该忽略还是处理这个问题? 据我所知,服务器也不会产生错误。 我想知道我是否未正确执行命令,或者未正确读取缓冲区。
以下是我的代码:
package main

import (
    "bytes"
    "fmt"
    "strings"

    "golang.org/x/crypto/ssh"
)

func main() {
    sshConfig := &ssh.ClientConfig{
        User: “my_username”,
        Auth: []ssh.AuthMethod{
            ssh.Password(“my password”),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
    connection, err := ssh.Dial("tcp", "localhost:22", sshConfig)
    if err != nil {
        fmt.Printf("Failed to dial: %s\n", err)
        return
    }

    defer func() {
        if err := connection.Close(); err != nil {
            fmt.Println("Received an error closing the ssh connection: ", err)
        } else {
            fmt.Println("No error found closing ssh connection")
        }
    }()

    session, err := connection.NewSession()
    if err != nil {
        fmt.Printf("Failed to create session: %s\n", err)
        return
    }

    defer func() {
        if err := session.Close(); err != nil {
            fmt.Println("Received an error closing the ssh session: ", err)
        } else {
            fmt.Println("No error found closing ssh session")
        }
    }()
    fmt.Println("created session")
    var stdOut bytes.Buffer
    var stdErr bytes.Buffer

    session.Stdout = &stdOut
    session.Stderr = &stdErr
    err = session.Run("pwd")
    fmt.Println("Executed command")

    fmt.Println("Command stdOut is:", strings.TrimRight(stdOut.String(), "\n"), " --- stdError is:", strings.TrimRight(stdErr.String(), "\n"))

}

我收到的输出是:
$ go run main.go
created session
Executed command
Command stdOut is: /Users/my_username  --- stdError is: 
Received an error closing the ssh session:  EOF
No error found closing ssh connection
$ 

有什么建议吗?

1个回答

3

这似乎类似于golang/go/issue 31401(然后引用了issue 32453:“x/crypto/ssh: 在调用session.Run()后运行session.Wait()的语义,当发送EOF消息时”)

返回该错误是因为会话已被关闭(由Run())。
SSH连接泄漏,因为它从未关闭 - 从Dial()返回的客户端对象被丢弃,但需要关闭该对象以清理底层TCP连接。

顺便说一下,这似乎是一个难以正确使用的API。
会话可以随时异步关闭,因此编写正确的代码始终可能从Close()获得EOF

因此,您可能希望测试特定的错误,并在defer函数中忽略它。


谢谢您的回复!您提供的内容很有道理,我明白了run = start + wait,但我仍然觉得在Close()中将EOF作为“错误”返回很奇怪。看看Close()是否应该为nil的干净/精确版本是正确的吗?我想这需要记录下来吧?或者可能修复为不返回EOF而是返回nil。 - ozn
@ozn "我仍然觉得有点奇怪":确切地说,这就是我提到的问题所在。这使得API使用起来相当棘手。 - VonC
谢谢。我会在 Golang 上开一个 bug,以更精确地处理这些事情。 - ozn
@ozn 好的,请告诉我问题的URL,我会跟进它。 - VonC
1
https://github.com/golang/go/issues/38115 让我们看看他们说了什么。 - ozn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接