关闭加密ssh会话释放golang中所有资源的正确方法?
TL;DR-关闭关闭加密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
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:callingSession.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)