Linux 中的 ssh 命令在连接到远程主机时,可以指定一个超时时间(ConnectTimeout),但是,细心的同学可能已经发现,即使指定了一个非常大的时间, 也不会生效。

这里就来分析下,为什么一个非常大的超时时间配置并不会生效。

首先,尝试连接一个不存在的主机

$ date;ssh -v 10.20.30.40; date
Mon Feb 13 16:37:11 CST 2017
OpenSSH_6.7p1 Debian-5+deb8u3, OpenSSL 1.0.1t  3 May 2016
debug1: Reading configuration data /home/chengwei/.ssh/config
debug1: /home/chengwei/.ssh/config line 195: Applying options for 10.*
debug1: /home/chengwei/.ssh/config line 199: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: Connecting to 10.20.30.40 [10.20.30.40] port 22.
debug1: connect to address 10.20.30.40 port 22: Connection timed out
ssh: connect to host 10.20.30.40 port 22: Connection timed out
Mon Feb 13 16:39:18 CST 2017

可以看到,大概 2 分 7 秒之后,连接失败,超时退出。

现在,指定超时时间为 5 秒

$ date; ssh -o ConnectTimeout=5 10.20.30.40; date
Sat Feb 18 11:56:28 CST 2017
ssh: connect to host 10.20.30.40 port 22: Connection timed out
Sat Feb 18 11:56:33 CST 2017

可以看到,5 秒钟后,ssh 即连接失败,超时退出。

那么,指定超时时间为 180 秒呢?

$ date; ssh -o ConnectTimeout=180 10.20.30.40; date
Sat Feb 18 11:57:47 CST 2017
ssh: connect to host 10.20.30.40 port 22: Connection timed out
Sat Feb 18 11:59:55 CST 2017

可以看到,超时时间并没有是 180 秒,而是 2 分 8 秒,只比 2 分 7 秒多 1 秒,甚至可以设置一个更大的超时, 也会发现,ssh 超时退出总是在 2 分 7 秒左右。

ssh 源代码

分析 ssh 连接到远程这部分相关代码,可以看到,ssh 在不配置 ConnectTimeout 选项时,默认使用 Linux 系统调用 connect(2) 来建立 TCP 连接,代码如下:

sshconnect.c:L340

if (*timeoutp <= 0) {
    result = connect(sockfd, serv_addr, addrlen);
    goto done;
}

而如果指定了 ConnectTimeout 选项时,ssh 会使用一个多路复用系统调用 select(2) 来等待连接,并且设定 ConnectTimeout 为 select 的超时参数。

sshconnect.c:L577

rc = select(connection_in + 1, fdset, NULL,
    fdset, &t_remaining);

而底层建立 TCP 连接,依然使用 connect(2) 系统调用,所以一旦 connect 超时(2 分 7 秒)时,select 的 stderr 这个 fdset 就变成 read ready 了, 所以 ssh 能够判断出失败了,从而退出或者开始新一轮尝试(ConnectionAttempts 选项)。

所以,ConnectTimeout 只能小于等于 Linux kernel 的 connect(2) 超时时间,大于并无意义;如果要获得更大的超时时间, 可以通过配置 ConnectionAttempts 来实现。

关于 Linux kernel 的 connect(2) 超时分析,请参考 Linux 建立 TCP 连接的超时时间分析