三次握手四次挥手
# 问题:讲一下TCP三次握手和四次挥手:
回答思路:三次握手->四次挥手->为什么不两次握手->为什么要设置等待时间
# 一. 三次握手
首先TCP三次握手是运输层建立连接的过程,三次握手主要解决3个问题:
- 每一方都能够确定对方的存在。
- 允许双方方协商一些参数。
- 能够对运输实体资源进行分配。
接下来讲一下主要流程:(主动方法连接的一方看做客户机,被动打开监听的一方看做服务器)
- 首先,客户机与服务器的
TCP
进程都处于CLOSED(关闭)状态,当要进行TCP
连接时,客户机主动打开连接,服务器被动打开连接,并处于listen监听状态 - 现在就可以开始真正的三次握手了。首先,客户机先向服务器发送连接请求报文段,该报文段中将首部中的同步位SYN置为
1
(只有当SYN置为1时,才能表明客户机想要和服务器建立连接),并且随机选择一个初始序号x,注意此时的SYN数据报中并没有携带数据,但是仍旧要消耗掉一个序号(意思就是下次客户机发送数据的时候,序号为x+1),此时客户机进入到SYN-SENT
(同步已发送)状态。 - 此时,服务器收到客户机的请求时,如果同意与该客户机进行连接,则需要向客户机发送确认报文。在发送报文中需要将SYN与ACK都置为1(当ACK置为1时,表明服务器同意与客户机进行连接;同时将SYN置为1,表明服务器想要和客户机建立连接),并且随机选择一个初始序号y,确认号为x+1(确认号表明服务器渴望收到的下一个报文段的第一个数据字节的序号,因为之前发送了x,所以下一个序号为x+1),注意此时的SYN数据报中并没有携带数据,但是也要消耗掉一个序号(同样的,也就是说服务器下次发送数据的时候,序号为y+1),此时TCP服务器进程进入到
SYN-RCVD
(同步收到)阶段。
顺便提一句,在这两个阶段会发送SYN Flooding
攻击,有兴趣可以自己搜索一下。
- TCP客户端收到服务器的确认后,还要再向服务器给出确认。确认报文段中ACK置为1,确认号为ack=y+1(因为之前服务器给客户机发送的序号为y,因此现在客户机向服务器发送的确认号为ack=y+1,意思是客户机渴望收到的下一个报文段的第一个数据字节为y+1)此时客户机的发送序号为x+1(这是因为刚才刚才客户机向服务器发送连接请求时消耗了序号x,因此此时的序号为x+1)注意:在进行第三次握手时,ACK报文段可以携带数据,也可以不携带数据,如果携带数据,则消耗一个序列,这样客户机下次发送报文段时的序号为x+2,如果不携带数据则不消耗序号,下次客户机发送报文段时的序号为x+1。这时TCP连接已经建立,客户机和服务器都进入到
ESTABLISHED
(已建立连接)状态
根据上述文章,可以引申出一下的问题:
# 1. 在三次握手中,可以不进行第三次握手吗?
这是为了防止已失效的连接请求报文段突然又传到了服务器所谓“已失效的连接请求报文段”是这样产生的。考虑一种正常的情况,客户机发出连接请求,但因为连接请求报文丢失而未收到确认。于是客户机再重传了一次连接请求,后来收到了确认,建立了连接。数据传输完后,就释放了连接。客户机共发送了两个连接请求报文段,其中第一个丢失,第二个到达了服务器,没有所谓的“已失效的连接请求报文段”。
但是如果出现了一种异常情况,即客户机发出的第一个报文段并没有丢失,而是在某个节点上长时间滞留了,直至客户机向服务器发送了第二个报文段并且已经完成数据传输释放了连接,此时,第一个报文到达服务器后会被误以为是客户机重新发起的一次连接请求,实质上是一个早已失效的连接请求。如果没有第三次握手,那么这个连接就建立了,但是客户机并不会向服务器发送任何请求,这样连接就会一直持续,白白的消耗网络资源。
# 二. 四次挥手
数据传输结束后,通信的双方都可以释放连接。此时,客户机和服务器都处于
ESTABLISHED
(已建立连接)状态。假设客户机请求完资源了,想要释放连接。首先,客户机的应用进程先向服务器发出连接释放报文段,该报文段中将首部的终止控制位FIN置为1(只有当FIN置为1时,才能表明客户机想要和服务器断开连接),并且序号为u(注意:此时的u不是随机产生的,而是之前客户机传送的数据的最后一个字节的序号加1)。此时客户机进入到
FIN-WAIT-1
(终止等待1)状态,等待服务器的确认。服务器收到连接释放报文后发出确认,在发送报文中将首部中的ACK置为1(ACK置为1,表面服务器同意与客户机释放连接),并且产生序号v(注意:此时的v不是随机产生的,而是之前服务器传送的数据的最后一个字节的序号加1),并且发出确认号为u+1(确认号表明服务器渴望收到的下一个报文段的第一个数据字节的序号,因为之前发送了u,所以下一个序号为u+1)。此时服务器就进入
CLOSE-WAIT
(关闭等待)状态,客户机进入FIN-WAIT-2状态。
此时,从客户机到服务器这个方向的连接就被释放了,也就是说,客户机已经没有数据要向服务器发送了,但是如果服务器向客户机发送数据,客户机仍要接收数据。也就是说:从客户机到服务器的连接已经被释放了,但是从服务器到客户机的连接还没被释放。此时,TCP连接处于半关闭状态。
如果服务器向客户机也没有要发送的数据的话,那么服务器的应用进程就可以向客户机发出连接释放报文段(注意此时还是服务器向客户机发送数据),该报文段中将首部的终止控制位FIN置为1(只有当FIN置为1时,才能表明客户机想要和服务器断开连接),ACK也置为1,并且序号为w(重点注意,此时的w不一定等于v+1。如果在客户机释放了连接之后,服务器向客户机仍旧发送了一部分数据,那么此时w不等于v+1,但是如果期间没有再发送数据,那么w就等于v+1。总而言之,这个w等于服务器上一次发送的数据的最后一个字节加1),并且发送确认号为u+1(确认号表明服务器渴望收到的下一个报文段的第一个数据字节的序号,因为之前发送了u,所以下一个序号为u+1)。此时服务器就进入了LAST-ACK(最后确认)状态。
客户机收到服务器的连接释放报文后,必须对此报文进行确认。在该报文段中将ACK置为1,确认号为w+1(确认号表明服务器渴望收到的下一个报文段的第一个数据字节的序号,因为之前发送了w,所以下一个序号为w+1),产生序号为u+1(因为上一个发送的数据的序号为u)。此时服务器进入到
TIME-WAIT
(等待时间)状态。但是,此时TCP连接还没有被释放掉。必须经过2MSL后服务器才能进入到CLOSED状态。(注:MSL叫做最长报文段寿命,RFC建议为两分钟,也就是说,要经过四分钟才能进入到CLOSED状态)。
# 1. 为什么客户机在第四次挥手后,还要等待2MSL呢?
第一:为了保证客户机最后发送的那个ACK报文段能够到达服务器。这个ACK报文段可能会丢失。因而使处在LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认。服务器会超时重传这个FIN+ACK报文段,而客户机就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着客户机重传一次确认,重新启动2MSL计时器,最后客户机和服务器都可以进入到CLOSED(关闭)状态。如果没有2MSL等待时间,那么就无法收到重传的FIN+ ACK包,无法进入正常的CLOSED状态。
第二,防止“已失效的连接请求报文段”出现在本连接中。客户机在发送完最后一个ACK报文段,再经过时间2MSL,就可以使本连接持续的时间内所产生的报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
# 2.如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
# 3.为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
# 三.扩展:SYN Flooding
# 1.半连接队列
在三次握手协议中,服务器维护一个半连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器 (opens new window)已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。 backlog参数:表示未连接队列的最大容纳数目。
# 2.SYN-ACK 重传次数
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同。
# 3. 半连接存活时间
是指半连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。
# 4.SYN攻击原理
SYN攻击属于DOS攻击的一种,它利用TCP协议 (opens new window)缺陷,通过发送大量的半连接请求,耗费CPU和内存资源。SYN攻击除了能影响主机外,还可以危害路由器、防火墙等网络系统,事实上SYN攻击并不管目标是什么系统,只要这些系统打开TCP服务就可以实施。从上图可看到,服务器接收到连接请求(syn=j),将此信息加入未连接队列,并发送请求包给客户(syn=k,ack=j+1),此时进入SYN_RECV状态。当服务器未收到客户端的确认包时,重发请求包,一直到超时,才将此条目从未连接队列删除。配合IP欺骗,SYN攻击能达到很好的效果,通常,客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。