TCP与UDP:原博客地址:https://blog.csdn.net/shanghairuoxiao/article/details/68927070
三次握手和四次挥手:原博客地址:https://blog.csdn.net/shanghairuoxiao/article/details/68927100
为什么不是两次和四次:https://blog.csdn.net/Runner1st/article/details/88242692
回答两次:①避免SYN洪泛攻击②讲解一种可能浪费资源的情况
①避免SYN洪泛攻击
在上面的讨论中我们知道,服务器收到一个SYN报文段时,分配并初始化连接变量和缓存,然后发送一个SYNACK进行响应。在收到来自客户端的ACK报文段之前,连接并没有完全建立,我们称它为半开连接 (half-open connection)。如果客户不发送ACK以完成三次握手的第三步,那么服务器会在一定时间内终止该半开连接,并回收分配的资源。
在这样的协议下,很容易被一种叫做SYN洪泛攻击 (SYN flood attack) 的拒绝服务攻击 (Denial of Service (DoS) attack) 侵袭。攻击者向服务器发送大量的TCP SYN报文段,而不完成三次握手的第三步,这样服务器不断为这些半开连接分配资源,导致服务器的连接资源消耗殆尽。
目前有一种防御机制可以抵御这种攻击,称为SYN cookie。
这种机制的思想在于,在收到SYN之后不马上进行分配资源(因为怕了),而是在第三步时判断连接的发起者是否为一个合法用户,如果是,再分配资源并建立连接。
首先,当服务器收到一个SYN时,不马上分配资源,而是按如下方式生成一个初始的序列号:该序列号是 “SYN报文段中的源和目的IP地址与端口号以及一个只有服务器自己知道的秘密数 (secret number) ” 的hash值,也就是说,只有知道这个秘密数,才可能算出这个序列号(这个初始序列号就称为“cookie”)。然后服务器就发送包含这个初始序列号的SYNACK。需要注意的是,服务器此时不维护任何关于该SYN的状态信息,甚至不用记住这个cookie值。所以如果客户没有返回一个ACK,那么对服务器来说就当什么时都没发生,现在SYN洪泛攻击就做不成了。
那么合法用户是怎样完成第三个步骤的呢?其实并没有什么改变,任然按照原来的方式进行,发送一个ACK给服务器。此时需要动点手脚的是服务端,服务端怎么判断这个ACK报文是对之前的SYNACK的确认呢?很简单,因为之前的SYNACK的序列号是根据“SYN报文段中的源和目的IP地址与端口号以及一个只有服务器自己知道的秘密数”算出来的,那么这次如果还是那个用户的话,那么源和目的IP地址与端口号是不会变的,然后秘密数服务端也知道,用原来的hash函数一算,就得出来了该序列号,然后加1,看是不是跟这个ACK报文的确认号相等,如果相等,那说明这个ACK对应之前的SYNACK,是合法的,于是创建一个连接。
②讲解一种可能浪费资源的情况
谢希仁版《计算机网络》对这个问题进行了讨论。总的来说,三次握手是为了防止当已失效的连接请求报文段突然又传到服务端,造成双方的不一致,导致资源的浪费。
“已失效的连接请求报文段”指的是这样的情况,客户端发出一个SYN报文段,由于阻塞或者其他原因在网络中滞留,以至于客户端认为丢包了(其实并没有丢),于是重新发出一个SYN报文段,假设这一次顺利完成了,那么双方建立连接。这看起来似乎没什么问题,但网络中有一个隐患,就是那个还在网络中传输的SYN报文段,如果这个SYN在连接期间被服务端收到了,那服务端只会无视它,这样就万事大吉了,但如果是在连接释放之后被收到呢?此时服务端认为有人向他发出连接请求,于是响应一个SYNACK回去,如果采用两次握手的话,那么服务器认为此时连接已经建立好了。但是当客户端收到这个SYNACK时,如果他并没有发起连接,那么他不会理睬这个SYNACK,就当没事发生过(如果客户端此时正好发起连接,那其实他也不会理睬这个SYNACK,因为确认号不对啊。)。那问题就大了,这时候服务器以为连接好了,向客户端发送数据,而客户端处于CLOSED状态,会丢弃这些包,这样就很浪费了。并且还有一个尴尬的问题,就是这个时候当客户端打算发起连接时,服务端又不理睬了,在这里尬这,他们就别想互发数据了。当然这些问题似乎不是不可解决的,当客户端发现服务端老是向自己发数据,而自己总是丢弃,可能会向服务端发一个RST(报文段的RST标记号为1),强制服务端关闭连接。但资源总归是浪费了一会了。而用三次握手就不会出现这样的问题。
回答四次:三次已经足够了,四次就会让费不必要的资源。