TCP被防火墙隔断引起的思考
基本情况说明:client和server分别在两部机器上,都是linux系统,都有防火墙,server开放一个端口让client连接,在client连接的一瞬间会发送一个注册包,server对于client发过来的包,任何时候都能接收成功的。但反过来server在刚连接的大概一分钟之内发送的一个包,client能收到,但此后发送的包client却不能成功接收,而且在第一个没有被接收的包开始计时,大概15分钟之后就会收到一个ICMP协议的EHOSTUNREACH(No route tohost)的错误 ,使用lsof查看两边的连接发现server这边的连接已经断开了,但client的连接还是存在的。
问题的分析:首先就被经验所误了,以为TCP能建立连接就跟防火墙没有关系,所以一直纠结在代码的问题上,结果查了一天没发现有问题,转而转向运维只得到一个关系不大的信息是两台机器都禁了ICMP,没办法还是得靠自己,使用strace查看系统调用发现server是发包成功的(这里要用上tcpdump才能确定),但在client那边却没有触发epoll的调用,最后让运维把client的防火墙关闭了,问题解决了。
整个过程看来本人水平确实很一般,但在其中涉及到几个问题还是值得我花点时间整理一下的。第一个问题是经验的包袱,这个肯定不是在说我自己了,而是在我把这个问题跟我的组长说明了一下之后,他认为不是防火墙的问题,导致了解决问题的方向出了一点小偏差。这是很多有经验程序员的一个通病。
第二个问题是client是主动去连server的,所以使用的是随机端口,而这个端口肯定是不在防火墙的列表中,由这个端口进来的包肯定会被阻拦。但另外TCP连接中的三次握手,第一次是client发送的SYN包,然后是server发过来的ACK包,这个包从上面的实际情况来看肯定不会被防火墙阻拦了(这点不太确定),而且更让我迷惑的是建立连接后大概一分钟内的server包,client也能接收,这个问题有待更进一步研究。
第三个问题是server这边检测到了连接断开,为什么client检测不到呢?运维说两部机器都是禁止了ICMP,所以不可能是靠ICMP来检测断线。上网看到了这样一篇文章http://www.ibm.com/developerworks/cn/aix/library/0808_zhengyong_tcp/,里面是说TCP 协议层的保活探测,这说明了TCP是如何检测并释放僵死的连接。而我查看了server机器的关于这方面的参数,允许的最大非活跃时间是20分钟,意思就是20分钟之后server才会检测到连接的断开,这和上面说到的15分钟有出入。而且我还发现如果server不发第二个包,连接是不会断开的,由此看出保活探测在我这种情况不靠谱。其实遇到这个问题之后第一时间就上网查,而并没有认真思考TCP的一些机制,这个习惯确实不好,这个问题其实第一时间应该想到的是TCP的重传机制,在TCP一直重传失败之后就会关闭连接了,情况就是这么简单。但保活探测没有效果,还有Client不会断开是因为server回复的ACK包不会被防火墙阻拦吗??这个问题有待进一步研究防火墙。