主机不可达和端口不可达不都是连接不上嘛,会有什么区别呢?果真如此吗,我们来写个小程序来试试,在地址的位置上,我们第一次使用一个不存在的主机IP,第二次使用一个存在的主机IP,但端口不存在。
public static void main(String[] args) throws Exception
{
Socket socket = new Socket();
InetSocketAddress addr = new InetSocketAddress("121.14.0.29", 12345);
socket.connect(addr);
}
在Linux环境下,对于不存在的端口(主机是linux),程序马上就报连接错误,而对于主机不存在,非常地糟糕,运行了很就一直没有返回,为什么会有这种区别呢(windows的测试结果会不太一样,后面会有说明)?我们使用Ethereal抓包来看一下有什么区别:
1.端口不存在
很幸运,对于端口不存在,对方(linux)在IP层会直接发一个RST(Reset)响应直接终止掉连接,客户端直接把连接终止。在Windows环境下不太一样, 如果对方为Windows服务器,则不会回RST响应,这种情况下与主机不存在一致。
2.主机不存在
很不幸,在TPC/IP的Linux环境的实现中,客户端在连接请求包没有得到响应的时候,会不断进行重试(实现认为可能是丢包),时间间隔分别是2秒/6秒/12秒/25秒/50秒(指数级增长,到达50秒后会以这个频度重试,在本机测试的时候(Rethat Linux Enterprise V4)一直持续了3分9秒。这样当然非常地糟糕,所以在连接的时候设置一下超时时间是非常地重要滴(见下面)。在Windows环境下结果不太一样,Windows的TCP/IP实现上,客户端只会重试一次,间隔是10秒钟。
socket.connect(addr, 300); //设置超时时间为300豪秒
另外有一件非常奇怪的事情,就是不管是主机不存在还是端口不存在,网关和主机并不会返回主机不存在或端口不存在的ICMP消息