关闭加密ssh会话释放golang中所有资源的正确方法?

关闭加密ssh会话释放golang中所有资源的正确方法?,go,ssh,pipe,Go,Ssh,Pipe,TL;DR-关闭golang.org/x/crypto/ssh会话释放所有资源的正确方法是什么 到目前为止,我的调查: golang.org/x/crypto/ssh*会话有一个Close()函数,它调用*频道Close()函数,该函数发送一条消息(我猜是到远程服务器)来关闭,但是我没有看到任何关于关闭其他资源的内容,比如从*会话返回的管道StdoutPipe()函数 查看*会话等待()代码,我看到*会话stdinPipeWriter已关闭,但与stdoutPipe无关 这个包感觉很像os/ex

TL;DR-关闭
golang.org/x/crypto/ssh
会话释放所有资源的正确方法是什么

到目前为止,我的调查:

golang.org/x/crypto/ssh
*会话
有一个
Close()
函数,它调用
*频道
Close()
函数,该函数发送一条消息(我猜是到远程服务器)来关闭,但是我没有看到任何关于关闭其他资源的内容,比如从
*会话返回的管道
StdoutPipe()
函数

查看
*会话
等待()
代码,我看到
*会话stdinPipeWriter
已关闭,但与
stdoutPipe
无关

这个包感觉很像
os/exec
包,它保证使用
os/exec Wait()
函数将清理所有资源。在那里进行一些简单的挖掘可以看出
Wait()
函数中的一些相似之处。两者都使用以下结构来报告
io.Copy
调用到其stdout、stderr、stdin读取器/写入器的错误(如果我正确阅读了这篇文章,实际上只有一个错误)-加密包显示:

var copyError error
for _ = range s.copyFuncs {
    if err := <-s.errors; err != nil && copyError == nil {
        copyError = err
    }
}
它只是在
io的一片上调用close方法。Closer
接口:

func (c *Cmd) closeDescriptors(closers []io.Closer) {
    for _, fd := range closers {
        fd.Close()
    }
}
os/exec
创建管道时,它会跟踪需要关闭的内容:

func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
if c.Stdout != nil {
    return nil, errors.New("exec: Stdout already set")
}
if c.Process != nil {
    return nil, errors.New("exec: StdoutPipe after process started")
}
pr, pw, err := os.Pipe()
if err != nil {
    return nil, err
}
c.Stdout = pw
c.closeAfterStart = append(c.closeAfterStart, pw)
c.closeAfterWait = append(c.closeAfterWait, pr)
return pr, nil
}

在此期间,我注意到
x/cyrpto/ssh
*会话StdoutPipe()
返回一个
io.Reader
ox/exec
返回一个
io.ReadCloser
。而且
x/crypto/ssh
不跟踪要关闭的内容。我在库中找不到对
os.Pipe()
的调用,因此可能实现不同,我遗漏了一些内容,并被管道名称弄糊涂了

通过调用
Close()
关闭会话。没有涉及任何文件描述符,也没有对
os.Pipe
的任何调用,因为从
会话返回的“Pipe”。StdOutPipe
在概念上只是一个管道,属于
ssh.Channel
类型。Go通道不需要关闭,因为关闭通道不是清理操作,而只是发送到通道的一种消息类型。ssh传输中只涉及一个网络连接

您需要关闭的唯一资源是网络连接;没有其他要释放的系统资源。在
ssh.Client
上调用
Close()
将调用
ssh.Conn.Close
,然后依次关闭
net.Conn

如果您需要处理网络连接,您可以随时跳过
ssh.Dial
便利功能,自己拨打网络连接:

c, err := net.DialTimeout(network, addr, timeout)
if err != nil {
    return nil, err
}
conn, chans, reqs, err := ssh.NewClientConn(c, addr, config)
if err != nil {
    return nil, err
}

// calling conn.Close will close the underlying net.Conn

client := ssh.NewClient(c, chans, reqs)

谢谢你的详细解释。因此,清除对
Session.Wait()
的调用后,应接着调用
Session.Close()
以实现无泄漏使用?此外,我的理解是,虽然通道本身不需要关闭,但在通道上调用Close可用于向上游或下游goroutine发出信号,表示不应发送/接收更多信息。这是因为,如果goroutine试图在一个从未从/发送到的无缓冲通道上发送/接收,它可能会挂起/泄漏,对吗?@darkwing:calling
Session.Close()
更多的是关于正确使用ssh协议,即通知服务器您希望关闭通道。实际上,接收到服务器的close消息会从多路复用器中删除ssh“channel”数据结构。是的,关闭go通道可以触发清理或取消阻止goroutines,但只有当代码以这种方式构造时。没有理由认为不关闭一个频道会比你可以采取的任何其他行动更容易泄漏资源。很好的澄清。我的第一条评论的答案是否定的,
Session.Wait()
接收服务器的关闭消息,并且(刚刚测试过)在
Session.Wait()之后调用
Session.close()
会给出一个EOF错误<代码> session .Cutely.()/>代码只需要在会话中间发生奇怪的事情时使用,我们想要退出——就像一个错误调用“代码> session .STDOutPipe())<代码>或<代码> session >请求文件()/<代码>
c, err := net.DialTimeout(network, addr, timeout)
if err != nil {
    return nil, err
}
conn, chans, reqs, err := ssh.NewClientConn(c, addr, config)
if err != nil {
    return nil, err
}

// calling conn.Close will close the underlying net.Conn

client := ssh.NewClient(c, chans, reqs)