有很多情况导致连接无法建立。
本文我们分析 2 种情况,分别是针对 Windows 和 Linux 进行讨论,它们是有区别的。
- 第一种情况是连接的主机不在网络中
- 第二种情况是主机在网络中,但是对应的服务未开启
不同版本的 Linux 内核也是有区别的。这里我使用的是 Ubuntu 14.04 LTS 版本。
1. 相关网络地址对应关系
在这里牵扯的 ip 地址有点多,可能会让你乱。我解释一下:
- 我的宿主机有两个 ip 地址,一个是本地网卡的地址:192.168.166.107,另一个是虚拟网卡 192.168.80.2
- 虚拟机中的 Linux 用的也是虚拟网卡,ip 地址是 192.168.80.130
实验中,我们去连接一个不存在的主机 192.168.165.2,,,如何确定这个主机不存在,你去 ping 一下这个 ip 地址就知道了。
2. 主机不在网络中
2.1 Linux 上的测试
在 Linux 上使用 tcpdump 命令进行抓包。cli 程序的路径是 unp/tools/tcpclient/cli.c
.
- 首先启动 tcpdump
$ sudo tcpdump port 5000
- 再开一个终端连接一个不存在的主机,注意这个 ip 地址不要和你的 Linux 在同一个网段,我的 Linux 主机 ip 是 192.168.80.130,是 80 网段,要连接的是 165 网段。
$ ./cli 192.168.165.2 5000
ip 地址为 192.168.165.2 这个主机是不存在的,但是客户端并不清楚此主机是否在网络中。
这里连续实验了两次,结果如图 1 和 图 2.
图1 第一次实验
图2 第二次实验
在图中,我用红字标明了一个相对时间,左侧的时间表示距离第一次发 SYN 的时间。而括号中的时间表示距离上一次发 SYN 的时间。
两次实验中,我们可以分析出以下结果:
- 客户端发送了 SYN 请求后,因为超时,重传了 4 次。
- 第一次超时约 1 秒后重传,第二次超时约 2 秒后重传,第三次是 4 秒,第四次是 8 秒。
- 第六次,是由主机 192.168.165.2 这个主机(实际上这个主机并不存在)回送的 RST 段。
2.2 Window 7 上的测试
首先在 Windows 7 上打开 OmniPeek,网卡选你上网的那个,不要选虚拟机网卡。
接下来使用 tcp_client 去连接 192.168.165.2 主机。我的 Window 7 ip 地址是 192.168.166.107. 同样的,不要让目标 ip 地址和连接的主机在同一个网段。
- 打开 OmniPeek 开始抓包
- 打开 cmd,连接目标主机
F:\tools> tcp_client 192.168.165.2 5000
在 Win7 上进行了三次实验,结果如图 3.
图 3 Windows 上的三次测试
从图 3 中可以看到,Windows 第一次发送完 SYN 段后,没有等到对端 ACK,进行了 2 次重传。也就是一共发送了 3 次 SYN 段,如果第 3 次发送的 SYN 还没有收到 ACK,超时后 connect 函数就直接返回错误。
另外,我们发现,第一次的超时时间约为 3 秒,第二次约为 6 秒。
3. 主机在网络中,但是服务未启动
3.1 Linux 上的测试
这里只进行了一次测试。实验和前面的区别就是要连接的主机就是我的 Windows.
./cli 192.168.166.107 5000
图4 连接 Windows 主机
从图 4 的结果来看,Linux 发送 SYN 段给目标主机后,对端直接丢了个 RST 段过来^_^,然后 connect 函数直接返回错误啦。。。。
3.2 在 Windows 上的测试
在 Windows 上使用 tcp_client 去连接 Linux。
tcp_client.ext 192.168.80.130 5000
图5 Windows 上的测试
可以看到,Windows 脸皮是比较厚的,对方丢了个 RST 段过来,仍然不放弃,又发两次 SYN 段。
4. 总结
- 知道 TCP 对于连接建立异常如何处理的
- 知道 Windows 和 Linux 是有区别的