三次握手
三次握手过程
- B 处于 LISTEN(监听)状态,等待来自 A 的连接请求。
- A 向 B 发送连接请求报文 SYN。
- B 收到 A 发来的 SYN,如果同意建立连接,则向 A 发送连接确认报文 SYN ACK。
- A 收到 SYN ACK 后,还要向 B 发出确认报文 ACK。
- B 收到 ACK 后,连接建立。
应该注意到,接收了 SYN 之后的所有报文都存在 ACK 字段。
三次握手的原因
第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。
四次挥手
四次挥手过程
-
A 发送连接释放报文 FIN。
-
B 收到 FIN 之后发出确认 ACK,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
-
当 B 不再需要连接时,发送连接释放报文 FIN。
-
A 收到 FIN 后发出确认 ACK,进入 TIME-WAIT 状态,等待 2 倍的 MSL(最大报文存活时间)后释放连接。
-
B 收到 ACK 后释放连接。
四次挥手的原因
客户端发送了 FIN 连接释放报文之后,服务器端收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器端会发送 FIN 连接释放报文。
TIME_WAIT
客户端接收到服务器端的 FIN 报文后进入此状态,而并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
-
确保最后一个确认报文 ACK 能够到达。如果服务器端没收到客户端发送来的确认报文 ACK,那么就需要重新发送连接释放请求报文 FIN,客户端等待一段时间就是为了处理这种情况的发生。
-
等待一段时间是为了让本次连接持续时间内产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文 SYN,从而错误打开连接。
抓包演示
使用 Wireshark 进行抓包,最开始使用 tcp 过滤器来进行观察,得到想要分析的 ip 地址 223.111.209.218。
观察到下面的四个包,分别表示:
-
List item
-
192.168.199.141 发出 SYN 连接请求报文 ;
-
223.111.209.218 接收到连接请求之后返回 SYN ACK 确认报文;
-
192.168.199.141 进行最后确认返回 ACK 报文;
-
192.168.199.141 发起 HTTP GET 请求。
再观察到以下五个包,分别表示: -
192.168.199.141 发出连接释放报文 FIN ACK;
-
223.111.209.218 返回 ACK 确认报文;
-
此时 TCP 处于半关闭状态,223.111.209.218 继续发送还未发送完的 HTTP 响应报文;
-
223.111.209.218 不再需要发送数据之后,发出连接释放报文 FIN ACK;
-
192.168.199.141 最后确认,返回 ACK 报文。
我们再举例来说
假如您是服务端,我是客户端,您是处于一直监听的状态,我现在发送一个请求,您接受到我发起的连接请求后,返回报文给我表示您已收到我发送的连接请求,我再次向您(服务端)发送确认收到允许链接的请求,总共三次(我→你,我←你,我→你),经过三次握手请求建立成功。
接下来再说一下为什么需要三次握手,其实是为了防止服务端开启过多连接,造成资源浪费,如果说我发送请求的过程中网络迟滞了,很长时间才到达您那边,这时候我认为之前的请求发送失败了,我会重新发送请求,然而之前我发送的请求经过很长时间你收到了并返还给我允许连接的报文,然而我已经重新发送了请求,认为之前的请求已经废弃,我不会进行第三次握手,去使用原来的废弃请求,这样服务器就不会在原来废弃请求的基础上创建连接,所以需要第三次握手