目录
首先,“双端”(“客户端”和“服务器端”)建立连接并且申请资源需要完成TCP协议的“三次握手”过程,然后,双端方可进行“数据交换”,最后,“双端”断开连接并且释放资源需要完成TCP 协议的“四次挥手”过程。
1、TCP 的三次握手+两次交换+四次挥手
1.1、三次握手
1.1.1、流程
第一次握手:当“客户端”发出SYN报文后,“客户端”进入SYN_SENT状态,等待“服务器端”的确认。
第二次握手:当“服务器端”收到SYN报文后,“服务器端”发出SYN+ACK报文,并进入SYN_RCVD状态,等待“客户端”的确认。
第三次握手:当“客户端”收到SYN+ACK报文后,“客户端”发出ACK报文,并进入ESTABLISHED状态。当“服务器端”收到ACK报文后,“服务器端”进入ESTABLISHED状态,完成三次握手。
1.1.2、两次握手为什么不可以?
-
如果“客户端”和“服务器端”只完成两次握手就建立连接,那么在“数据交换”的时候“服务器端”不知道对方(“客户端”)是否具有read能力。
-
如果“客户端”和“服务器端”只完成两次握手就建立连接,同时,第二次握手报文丢失,后续“客户端”跟“服务器端”的“数据交换”就无法继续下去(“客户端”无法知道“服务器端”传输过来的SYN+ACK报文信息中的初始化Seq序列号,就无法计算得到“客户端”向“服务器端”进行“数据交换”期间的Ack值)。
-
由于“服务器端”不知道“客户端”是否具有read能力,在完成两次握手就建立连接,那么会加大“服务器端”的安全隐患,比如黑客频繁的发起两次握手,“服务器端”申请资源建立连接导致资源耗尽。
-
第一次握手SYN报文的Seq值是随机生成的,如果两次握手就建立连接且第二次握手报文丢失,那么“服务器端”无法判断后续的报文对应的连接是否就是历史连接。
1.1.3、第一次握手是否可以携带数据?
第一次握手不可以携带数据。
假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的SYN报文中放入大量的数据,疯狂着重复发SYN报文,这会让服务器花费大量的内存空间来缓存这些报文,这样服务器就更容易被攻击了。
1.1.4、第二次握手是否可以携带数据?
第二次握手不可以携带数据。
1.1.5、第三次握手是否可以携带数据?
第三次握手可以携带数据。
1.1.6、TCP-SYN Flood攻击
TCP-SYN Flood攻击又称半开式连接攻击,是一个计算机编程术语。标准的TCP建立连接,都会经历“三次握手”的过程,而黑客进行TCP-SYN Flood攻击的时候只有前两个步骤,这样“服务器端”会在一定时间处于等待“客户端”的ACK报文。由于一台服务器可用的TCP连接是有限的,如果黑客频繁地发送此类连接请求,则服务器可用TCP连接队列很快将会阻塞,系统资源和可用带宽急剧下降,无法提供正常的网络服务,从而造成拒绝服务。
1.2、二次交换
为了保证数据准确到达,“服务器端”在收到数据包包后必须立即回传ACK包(包括SYN包、FIN包、普通数据包等),这样发送方才能确认数据传输成功。
此时Ack号为1301而不是1201,原因在于Ack号的增量为传输的数据字节数。假设每次Ack号不加传输的字节数,这样虽然可以确认数据包的传输,但无法明确100字节全部正确传递还是丢失了一部分,比如只传递了80字节。因此按如下的公式确认Ack号:
A
c
k
=
S
e
q
+
传递字节数
+
1
Ack=Seq+传递字节数+1
Ack=Seq+传递字节数+1
与三次握手协议相同,最后加1是为了告诉对方要传递的Seq号。
如果“客户端”到“服务器端”的数据包发生丢失,为了完成数据包的重传,“客户端”每次发送数据包时都会启动定时器,如果在一定时间内没有收到“服务器端”传回的ACK数据包,那么定时器超时了,“客户端”数据包会重传。
1.3、四次挥手
1.3.1、流程
第一次挥手:“客户端”发出FIN报文,并进入FIN_WAIT_1状态。
注意:此时,“客户端”不会向“服务器端”进行“数据交换”。
第二次挥手:当“服务器端”收到FIN报文后,“服务器端”发出ACK报文,并进入CLOSE_WAIT状态。当“客户端”收到ACK报文后,“客户端”进入FIN_WAIT_2状态。
注意:此时,如果“服务器端”还要向“客户端”进行“数据交换”,那么“服务器端”继续发送数据。
第三次挥手:当“服务器端”数据发送完毕后,“客户端”发出FIN报文,并进入LAST_ACK状态。
第四次挥手:当“客户端”收到FIN报文后,“客户端”发出ACK报文,并进入TIME_WAIT状态。当“服务器端”收到ACK报文后,“服务器端”进入CLOSED状态,完成四次握手。
注意:此时,“客户端”的TCP连接还没有释放,必须经过2*MSL(maximum segment lifetime)后才进入CLOSED状态。而“服务器端”收到“客户端”的ACK报文后就进入了CLOSED状态,可以看出“服务器端”比“客户端”结束连接的时间早。
1.3.2、为什么建立连接需要三次握手,断开连接需要四次挥手?
三次握手的时候,“服务器端”是将SYN和ACK数据合并到一个报文里面发送的。四次挥手的时候,“服务器端”是将FIN和ACK数据分开到二个报文里面发送的,将这两个报文分开发送的目的是能够保证“服务器端”能够把剩余的数据传输到“客户端”。
1.3.3、为什么“客户端”TIME_WAIT 状态需要经过2MSL才能返回到 CLOSE 状态?
原因1:在“服务器端”发送FIN报文后,“客户端”会发送的ACK报文,但是这个报文可能不可达。如果“服务器端”接收不到“客户端”的ACK报文,那么“服务器端”会重新发送FIN报文。所以“客户端”发送ACK报文后需要留出2MSL时间(ACK到达“服务器端”时间+“服务器端”重传发送FIN包时间)等待服务器收到了ACK报文;
原因2:MSL指的是报文在网络中的最大生存时间,通过2MSL的TIME_WAIT后,可以使本TCP连接“客户端”和“服务器端”产生的所有的报文都从网络中消失,以致避免新旧TCP连接出现冲突。