一、建立连接过程中的相关名词
序列号(Sequence Number,seq):由于数据分片传输,序号对每一片数据编号,确保接收端能够按照序号排列得到正确的数据
确认应答号(Acknowledge Number,ack):发送方期待接收的下一序列号,会在接收成功的数据报序号的基础上加1。只有ACK=1时才有效
ACK:确认序号的标志,ACK=1表示确认应答号有效,ACK=0表示报文不含确认应答号信息
SYN:连接请求序号标志,用于建立连接,SYN=1表示请求连接
FIN:结束标志,用于释放连接,为1表示关闭本方数据流
二、三次握手
三次握手过程
建立TCP连接时,需要客户端和服务器一共发送3个包
- 客户端发送初始序号x(随机生成)和syn=1请求标志
- 服务器发送请求标志syn,发送确认标志ACK,发送自己的序号seq=y,发送客户端的确认应答号为ack=x+1
- 客户端发送ACK确认号,发送自己的序号seq=x+1,发送对方的确认序号号为ack=y+1
三次握手过程分析
- 客户端发送请求到服务器,服务器知道客户端发送,自己接收正常。SYN=1,seq=x
- 服务器发给客户端,客户端知道自己发送、接收正常,服务器接收、发送正常.ACK=1,ack=x+1,SYN=1,seq=y
- 客户端发给服务器:服务器知道客户端发送,接收正常,自己接收,发送也正常。seq=x+1,ACK=1,ack=y+1
握手次数原因分析
- 从握手过程分析,我们就可以得出,只有经过三次握手,双方才能都得出自己、对方的接收、发送能力都正常的结论。
- 从应用场景中分析,我们可以看看两次握手下可能出现的问题。
在两次挥手的情况下,假设这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接收到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
三、四次挥手
四次挥手过程
释放TCP连接时,需要客户端和服务器一共发送4个包
- 客户端发出释放FIN=1,自己序列号seq=u,进入FIN-WAIT-1状态
- 服务器收到客户端的请求后,发出ACK=1确认标志和客户端的确认号ack=u+1,自己的序列号seq=v,进入CLOSE-WAIT状态
- 客户端收到服务器确认结果后,进入FIN-WAIT-2状态。此时服务器发送释放FIN=1信号,确认标志ACK=1,确认应答号ack=u+1,自己的序列号seq=w,服务器进入LAST-ACK(最后确认态)
- 客户端收到回复后,发送确认ACK=1,ack=w+1,自己的seq=u+1,客户端进入TIME-WAIT(时间等待)。客户端经过2个最长报文段寿命后,客户端CLOSE;服务器收到确认后,立刻进入CLOSE状态。
四次挥手过程分析
- 客户端请求断开FIN,seq=u
- 服务器确认客户端的断开请求ACK=1,ack=u+1,seq=v
- 服务器请求断开FIN,seq=w,ACK=1,ack=u+1
- 客户端确认服务器的断开ACK,ack=w+1,seq=u+1
挥手次数原因分析
三次握手时,服务器同时把ACK和SYN放在一起发送到了客户端那里
四次挥手时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送
四、相关问题
三次握手的第三次握手失败怎么办?
-
服务器端:并不会重传ack报文,而是根据超时重传机制直接发送RST报文段,如果次数达到上限还没有收到,就会关闭连接。
-
客户端:在发送了SYN+ACK包后,客户端就进入established状态,直到接收到服务器端返回的RST报文段,才会感知到错误,这时候会再次发送报文。
利用三次握手原理的SYN flood攻击的过程及解决方案
-
服务端在第二次握手时会发送给客户端一个SYN-ACK包来回应,同时服务端会保持端口开放来等待客户端回应的ACK包,这也是所谓的半开放连接状态。而恶意者可以通过创建很多的半开放式连接来发送SYN洪水攻击。
-
解决方案是SYN cookie,使用cookie来响应TCP SYN请求的TCP实现。服务端收到一个SYN包后,返回一个SYN-ACK包,这个包的序列号是经过加密的,然后服务端释放所有的状态。如果一个ACK包从客户端返回,服务端将重新计算它来判断它是不是上一个SYN-ACK的返回包。如果这样,服务端就可以直接进入TCP连接状态来打开连接,从而使服务端避免守候半开放状态。
也可以使用一个防火墙作为cookie的承载者中间件来抵御SYN flood攻击
四次握手最后为什么客户端还要等待2MSL?
-
客户端需要保证最后一次发送的ACK报文到服务器,如果服务器未收到,可以请求客户端重发,这样客户端还有时间再发,重启2MSL计时。
-
等待最大的2MSL可以让本次连接的所有网络包在链路上消失,以防造成不必要的干扰。比如,如果客户端直接关闭,然后又向服务端发起了一个新连接,我们不能保证这个新连接和刚关闭的连接的端口号是不同的。假设新连接和已经关闭的老端口号是一样的,如果前一次滞留的某些数据仍然在网络中,这些延迟数据会在新连接建立后到达服务端,服务端会认为这些延迟的数据属于新连接,数据包就会发生混淆。所以客户端要在TIME_WAIT状态等待2倍的MSL,这样保证本次连接的所有数据都从网络中消失。