Linux 中的 ssh 命令在连接到远程主机时,可以指定一个超时时间(ConnectTimeout),但是,细心的同学可能已经发现,即使指定了一个非常大的时间,
也不会生效。
这里就来分析下,为什么一个非常大的超时时间配置并不会生效。
首先,尝试连接一个不存在的主机
可以看到,大概 2 分 7 秒之后,连接失败,超时退出。
现在,指定超时时间为 5 秒
可以看到,5 秒钟后,ssh 即连接失败,超时退出。
那么,指定超时时间为 180 秒呢?
可以看到,超时时间并没有是 180 秒,而是 2 分 8 秒,只比 2 分 7 秒多 1 秒,甚至可以设置一个更大的超时,
也会发现,ssh 超时退出总是在 2 分 7 秒左右。
ssh 源代码
分析 ssh 连接到远程这部分相关代码,可以看到,ssh 在不配置 ConnectTimeout 选项时,默认使用 Linux 系统调用 connect(2)
来建立 TCP 连接,代码如下:
sshconnect.c:L340
而如果指定了 ConnectTimeout 选项时,ssh 会使用一个多路复用系统调用 select(2) 来等待连接,并且设定 ConnectTimeout 为 select 的超时参数。
sshconnect.c:L577
而底层建立 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 连接的超时时间分析。