dongzhangnong2063 2017-03-03 23:47
浏览 400
已采纳

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

TL;DR - What is the proper way to close a golang.org/x/crypto/ssh session freeing all resources?

My investigation thus far:

The golang.org/x/crypto/ssh *Session has a Close() function which calls the *Channel Close() function which sends a message (I'm guessing to the remote server) to close, but I don't see anything about closing other resources like the pipe returned from the *Session StdoutPipe() function.

Looking at the *Session Wait() code, I see that the *Session stdinPipeWriter is closed but nothing about the stdoutPipe.

This package feels a lot like the os/exec package which guarantees that using the os/exec Wait() function will clean up all the resources. Doing some light digging there shows some similarities in the Wait() functions. Both use the following construct to report errors on io.Copy calls to their stdout, stderr, stdin readers/writers (well if I'm reading this correctly actually only one error) - crypto package shown:

var copyError error
for _ = range s.copyFuncs {
    if err := <-s.errors; err != nil && copyError == nil {
        copyError = err
    }
}

But the os/exec Wait() also calls this close descriptor method

c.closeDescriptors(c.closeAfterWait)

which is just calling the close method on a slice of io.Closer interfaces:

func (c *Cmd) closeDescriptors(closers []io.Closer) {
    for _, fd := range closers {
        fd.Close()
    }
}

when os/exec creates the pipe, it tracks what needs closing:

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
}

During this I noticed that x/cyrpto/ssh *Session StdoutPipe() returns an io.Reader and ox/exec returns an io.ReadCloser. And x/crypto/ssh does not track what to close. I can't find a call to os.Pipe() in the library so maybe the implementation is different and I'm missing something and confused by the Pipe name.

  • 写回答

1条回答 默认 最新

  • duan7772 2017-03-03 23:57
    关注

    A session is closed by calling Close(). There are no file descriptors involved, nor are there any calls to os.Pipe as the "pipe" returned from Session.StdOutPipe is only a pipe in concept and is of type ssh.Channel. Go channels don't need to be closed, because closing a channel is not a cleanup operation, rather it's simply a type of message sent to the channel. There is only ever one network connection involved in the ssh transport.

    The only resource you need to close is the network connection; there are no other system resources to be freed. Calling Close() on the ssh.Client will call ssh.Conn.Close, and in turn close the net.Conn.

    If you need the handle the network connection, you can always skip the ssh.Dial convenience function and Dial the network connection yourself:

    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)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 STM32驱动继电器
  • ¥15 Windows server update services
  • ¥15 关于#c语言#的问题:我现在在做一个墨水屏设计,2.9英寸的小屏怎么换4.2英寸大屏
  • ¥15 模糊pid与pid仿真结果几乎一样
  • ¥15 java的GUI的运用
  • ¥15 我想付费需要AKM公司DSP开发资料及相关开发。
  • ¥15 怎么配置广告联盟瀑布流
  • ¥15 Rstudio 保存代码闪退
  • ¥20 win系统的PYQT程序生成的数据如何放入云服务器阿里云window版?
  • ¥50 invest生境质量模块