由于现在客户端并没有发出连接建立的请求,因此不会理会服务端的确认,也不会向服务端发送数据,但是服务端却以为新的传输连接已经建立了,并一直等待客户端发来数据,这样服务端的许多资源就这样白白浪费了。
采用三次握手的办法可以防止上述现象的发生。比如在上述的场景下,客户端不向服务端的发出确认请求,服务端由于收不到确认,就知道客户端并没有要求建立连接。
TCP四次挥手
TCP三次握手是TCP连接建立的过程,TCP四次挥手则是TCP连接释放的过程。下面是TCP四次挥手的流程图:
当客户端没有数据再需要发送给服务端时,就需要释放客户端的连接,这整个过程为:
客户端发送一个报文给服务端(没有数据),其中FIN设置为1,Sequence Number置为u,客户端进入FIN_WAIT_1状态
服务端收到来自客户端的请求,发送一个ACK给客户端,Acknowledge置为u+1,同时发送Sequence Number为v,服务端年进入CLOSE_WAIT状态
服务端发送一个FIN给客户端,ACK置为1,Sequence置为w,Acknowledge置为u+1,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态
客户端收到FIN后,进入TIME_WAIT状态,接着发送一个ACK给服务端,Acknowledge置为w+1,Sequence Number置为u+1,最后客户端和服务端都进入CLOSED状态
为什么建链接要3次握手,断链接需要4次挥手?
对于建链接的3次握手,主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——所以叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。
对于4次挥手,其实你仔细看是2次,因为TCP是全双工的,所以,发送方和接收方都需要Fin和Ack。只不过,有一方是被动的,所以看上去就成了所谓的4次挥手。如果两边同时断连接,那就会就进入到CLOSING状态,然后到达TIME_WAIT状态。下图是双方同时断连接的示意图(你同样可以对照着TCP状态机看):
使用Wireshark抓包验证TCP三次握手过程
为了加深对TCP三次握手的理解,抓包看一下TCP三次握手的过程。
抓包下来的内容为:
这里多说一句,由于wireshark抓包针对的是网卡,因此只要某张网卡上有网络访问,就会有数据包,这会导致Wireshark的抓包结果里面会有大量数据包,而大多数都不是想要的,这种情况可以使用Wireshark的过滤规则。我这里由于知道目标ip,因此使用的是"ip.src == xxx.xxx.xxx.xxx or ip.dst == xxx.xxx.xxx.xxx"这条规则只过滤特定的ip。
从抓包结果看来,整个过程符合TCP三次握手的预期:
客户端发送SYN给服务端
服务端返回SYN+ACK给客户端
客户端确认,返回ACK给服务端
至于Sequence Number和Acknowledge Number就不看了,但是注意,前面说了Sequence Number是随机产生的一个值,但是这里确是0,不光这里是0,抓其他的任何包这个值都是0。但其实这里并不是真的0,而是Wireshark为了显示更好阅读,使用了relative sequence number相对序号,Sequence Number具体值我们也是可以看到的:
第一个红框就是上面说的relative sequence number,第二个红框就是Sequence Number的真实值0xc978aa7e,转换为十进制为3380128382,就是随机产生的Sequence Number。
顺便能看到,下一个数据包就是HTTP���数据包,因为TCP三次握手已完成,连接建立,正式传输应用层数据,传输的HTTP内容大小为704字节。