SSH客户端"SSH Broken Pipe"问题

SSH客户与服务端建立连接后闲置一段时间,再次使用时出现"SSH Broken Pipe”: 客户端发出数据包后,服务器返回的是RST包:

由于是NAT网络,这种情形可以做如下解释

当客户与服务器建立TCP连接时,NAT设备中会产生一个对应于该连接的Session,NAT利用这个Session来完成内外网IP:Port的转换(IP内:Port内 - IP外:Port外)。而这个Session并非一直存在,若连接关闭或者超过一定时长没有流量通过的话,Session就被释放了。

这里"闲置"的时间应该是超过了Session的容忍时长,所以,最初的那个Session已经不存在了,当再次向服务端发送数据包时,NAT就会启用一个全新的Session,新旧Session的区别在于:二者的"Port外"是不同的(也有可能相同,这依赖于NAT的实现)。

"Port外"发生变化,就导致从NAT发出去的数据包的"源端口"号发生变化,最终引起了服务端的困惑。因为它收到了一个数据包,这个包中的源TCP端口号居然不是当初与自己建立连接的那个端口号,服务端不知道下一步该做什么,于是就发送了"RST"包,要求关闭连接。

解决办法(OSX系统)

启动客户端心跳机制,保证最初的NAT Session不被释放即可,在SSH客户端配置中设置"ServerAliveInterval"项,单位为秒。

全局配置(对系统内所有用户都生效)

编辑"/etc/ssh_config"文件,加入:

ServerAliveInterval 20

只针对当前用户

编辑"~/.ssh/config"文件,若不存在就直接创建,加入:

ServerAliveInterval 20