SSH连接超时 [英] SSH Connection Timeout

查看:186
本文介绍了SSH连接超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试使用 golang.org/x/crypto/ssh 建立SSH连接,我有点儿惊讶于我似乎无法找到如何超时 NewSession 函数(我实际上没有看到任何超时的方法)。当我尝试连接到有问题的服务器时,这只会持续很长时间。我已经写了一些东西用选择 time.After 之后,但它只是感觉像一个黑客。我还没有尝试过的东西是保持底层 net.Conn 在我的结构中,并继续做 Conn.SetDeadline()电话。还没有尝试过这一点,因为我不知道crypto / ssh库是否覆盖了这个或者类似的东西。

I am trying to make SSH connections using golang.org/x/crypto/ssh and I am kinda surprised that I can't seem to find out how to timeout the NewSession function (I actually don't seen any way to timeout anything). When I try to connect to a server that is having issues, this just hangs for a very long time. I have written something to use select with a time.After but it just feels like a hack. Something I haven't tried yet is to keep the underlying net.Conn in my struct and just keep doing Conn.SetDeadline() calls. Haven't tried this yet because I don't know if the crypto/ssh library overrides this or anything like that.

任何人都有一个很好的方法来用这个库?还是有人知道更好的库?

Anyone have a good way to timeout dead servers with this library? Or does anyone know of a better library?

推荐答案

用ssh包透明地处理这个问题的一种方法是创建一个连接通过自定义 net.Conn 设置空闲超时,为您设置最后期限。但是,这会导致连接的后台读取超时,所以我们需要使用ssh keepalives来保持连接处于打开状态。根据您的使用情况,只需使用ssh keepalives作为死连接的警报即可。

One way to handle this transparently with the ssh package, is to create a connection with an idle timeout via a custom net.Conn which sets deadlines for you. However, this will cause the background Reads on a connection to timeout, so we need to use ssh keepalives to keep the connection open. Depending on your use case, simply using ssh keepalives as an alert for a dead connection may suffice.

// Conn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type Conn struct {
    net.Conn
    ReadTimeout  time.Duration
    WriteTimeout time.Duration
}

func (c *Conn) Read(b []byte) (int, error) {
    err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
    if err != nil {
        return 0, err
    }
    return c.Conn.Read(b)
}

func (c *Conn) Write(b []byte) (int, error) {
    err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
    if err != nil {
        return 0, err
    }
    return c.Conn.Write(b)
}



然后,您可以使用 net.DialTimeout net.Dialer 来获取连接,并将其包装在您的 Conn 超时,并将它传递给 ssh.NewClientConn

You can then use net.DialTimeout or a net.Dialer to get the connection, wrap it in your Conn with timeouts, and pass it into ssh.NewClientConn.

func SSHDialTimeout(network, addr string, config *ssh.ClientConfig, timeout time.Duration) (*ssh.Client, error) {
    conn, err := net.DialTimeout(network, addr, timeout)
    if err != nil {
        return nil, err
    }

    timeoutConn := &Conn{conn, timeout, timeout}
    c, chans, reqs, err := ssh.NewClientConn(timeoutConn, addr, config)
    if err != nil {
        return nil, err
    }
    client := ssh.NewClient(c, chans, reqs)

    // this sends keepalive packets every 2 seconds
    // there's no useful response from these, so we can just abort if there's an error
    go func() {
        t := time.NewTicker(2 * time.Second)
        defer t.Stop()
        for {
            <-t.C
            _, _, err := client.Conn.SendRequest("keepalive@golang.org", true, nil)
            if err != nil {
                return
            }
        }
    }()
    return client, nil
}

这篇关于SSH连接超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆