【发布时间】:2020-02-15 22:37:28
【问题描述】:
我已经编写了一个 SSH 客户端来连接到网络设备,一旦运行命令超过 25 秒,我就会通过“选择”设置超时。我注意到一些设备有另一个 IOS,一旦触发超时,它就无法通过 Close() 方法丢弃与它们的 SSH 会话,这会导致 goroutinge 泄漏。我需要跟上客户端并断开会话以准备下一个命令。看起来 goroutine 在那个时候不会永远终止!你们有什么想法吗?
go func() {
r <- s.Run(cmd)
}()
select {
case err := <-r:
return err
case <-time.After(time.Duration(timeout) * time.Second):
s.Close()
return fmt.Errorf("timeout after %d seconds", timeout)
}
通过堆分析,我看到了以下内容: 2.77GB 99.44% 99.44% 2.77GB 99.44% bytes.makeSlice
0 0% 99.44% 2.77GB 99.44% bytes.(*Buffer).ReadFrom
0 0% 99.44% 2.77GB 99.44% golang.org/x/crypto/ssh.(*Session).start.func1
0 0% 99.44% 2.77GB 99.44% golang.org/x/crypto/ssh.(*Session).stdout.func1
0 0% 99.44% 2.77GB 99.44% io.Copy
0 0% 99.44% 2.77GB 99.44% io.copyBuffer
0 0% 99.44% 2.78GB 99.93% runtime.goexit
ROUTINE ======================== runtime.goexit in /usr/local/go/src/runtime/asm_amd64.s
0 2.78GB (flat, cum) 99.93% of Total
. . 1993: RET
. . 1994:
. . 1995:// The top-most function running on a goroutine
. . 1996:// returns to goexit+PCQuantum.
. . 1997:TEXT runtime·goexit(SB),NOSPLIT,$0-0
. 2.78GB 1998: BYTE $0x90 // NOP
. . 1999: CALL runtime·goexit1(SB) // does not return
. . 2000: // traceback from goexit1 must hit code range of goexit
. . 2001: BYTE $0x90 // NOP
. . 2002:
. . 2003:TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
【问题讨论】:
-
r通道是否被缓冲?当您超时时,没有接收者可以接受来自s.Run的结果。您可能仍然需要实际终止远程进程;您是否尝试过在超时时使用s.Signal杀死它? -
再次,
r是否已缓冲? -
需要缓冲,否则goroutine无法返回。
-
不要关闭会话以中止,杀死进程并等待它(运行正在调用等待你)
-
我相信 s.Run 触发的进程没有正确停止,因此它无法释放资源。您是否尝试将 sigterm/sig kill 发送到该进程? godoc.org/golang.org/x/crypto/ssh#Session.Signal 而不是运行,而是使用开始并等待 stackoverflow.com/questions/11886531/…