记录TCP三次握手和四次挥手

197 阅读7分钟

什么是TCP?

TCP,传输控制协议(Transmission Control Protocol),是一种面向链接的、可靠的、基于字节流的传输层通信协议。是为了在不可靠的互联网络上提供可靠的端到端的字节流而专门设计的一个传输协议。比如说:从个人电脑浏览器到远程服务器,也就是客户端、服务器端。 既然是远程的链接,怎么保证链接和断开的可靠性呢?链接靠的式三次握手,断开是四次挥手。

什么是三次握手?

看个三次握手的动画,三次握手确定了,客户端的收发报文的能力正常和服务端收发报文的能力正常,为接下来的数据传输做准备。

image.png

刚开始客户端处于Closed状态

  1. 第一次握手:客户端发送一个SYN报文,并指明客户端初始化序列号ISN,此时客户端状态为SYS_SEND状态。
  2. 服务端收到客户端SYN报文之后,以自己的SYN报文作为应答,同样指定自己的初始化序列号ISN,同时把客户端的ISN+1作为ACK的值,表示自己已经收到了客户端的SYN,此时服务器处于SUN_REVD状态。
  3. 客户端收到SYN报文之后,会发送一个ACK报文,当然也是以服务端ISN+1作为ACK的值,表示已经收到了服务端的SYN报文,此时,客户端处于ESTABLISHED状态,服务端收到ACK报文后也处于ESTABLISHED状态,此时,客户端和服务端已经建立起链接。
为什么是三次握手而不是两次

三次握手的目的是什么,

  1. 第一次客户端发包,服务端收到了

    服务端知道客户端发包能力服务端接收能力正常。

  2. 第二服务端发包,客户端收到了

    客户端知道服务端的发包能力和接收能力正常,客户端的发送接收能力正常,但是现在,服务端不知道客户端的接收能力是否正常,也就是服务端不知道第二次握手发送的报文,客户端有没有收到,

  3. 客户端发包,服务端接收到了 这样服务端就能得出结论:客户端的收发能力正常,服务端的收发能力正常

从上得知,如果只是两次握手并不能确定客户端接收报文能力是否正常,这样直接建立链接肯定是有风险的。

什么是半连接队列?

服务器端第一次收到ACK报文,处于SYN_RCVD状态,此时双方没有完整的建立链接,服务器会把这种状态下的请求放到一个队列列边,这个队列就叫做半连接队列;完成三次握手后,就会放在全连接队列里边。如果队列满了就可能出现丢包。

ISN是固定的吗?

ISN随时间而变化,是不同的,ISN可以看做是一个32比特的计数器,每4ms加一,这样选择序列号的目的是防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方做出错误的解释。

三次握手可以携带数据吗?

第三次握手可以,其余不可以,如果前两次可以发送数据,客户端或者服务端需要额外花费时间去处理数据,如果被恶意攻击会消耗客户端或者服务端大量的内存、时间来处理,阻塞接下来的流程。第三次握手,客户端已经处于ESTABLISHED状态,知道服务器收发能力正常,可以携带数据。

什么是SYN攻击

SYN攻击就是client短时间伪造大量的虚假IP地址,向server发送大量的SYN报文,server大量回复SYN报文,由于IP地址不存在,导致无法收到确认,server需要不停的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致真正的SYN报文因为队列满而被丢弃,从而引起网络拥塞甚至瘫痪。SYN是一种典型的Dos/DDoS攻击。 检测SYN攻击很简单,当你在服务器检测到大量的半链接队列,IP地址是随机的,基本上就可以判定这是一次SYN攻击。在Linux/unix用netstats命令来检测SYN攻击

netstat -n -p TCP | grep SYN_RECV

常见的防御SYN攻击方法:

  • 缩短超时(SYN Timeout)时间
  • 增加最大半连接数
  • 过滤网官防护
  • SYN Cookies技术

四次挥手

image.png 四次挥手的作用是释放链接,也叫四次握手,

  1. 第一次挥手:客户端发送FIN报文,报文中会指定一个序列号,此时客户端处于FIN_WAIT1的状态。
  2. 第二次挥手:服务端收到FIN后,会发送ACK报文,且把客户端的序列号值+1作为ACK报文的序列号值,表明已经收到客户端报文了,此时服务端状态为CLOSE_WAIT状态。
  3. 第三次挥手:如果服务端也想断开链接了,也想客户端第一次挥手一样,发送FIN报文,指定一个序列号,此时服务端处于LAST_ACK状态。等待客户端确认。
  4. 第四次挥手:客户端收到FIN报文之后,一样发送一个ACK报文作为应答,且把服务端的序列号值+1作为ACK报文的序列号值,此时客户端处于TIME_WAIT状态。需要过一阵子,确认服务端收到ACK报文之后,才会进入CLOSED状态,服务端收到ACK报文之后,就关闭链接了,处于CLOSED状态。

image.png

客户端进入TIME_WAIT状态,此时TCP并未释放掉,需要经过时间的等待计时器的时间设置2MSL后,客户端才会进入CLOSED状态。

为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?

TIME_WAIT状态也称为2MSL状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)它是任何报文段被丢弃前在网络内的最长时间。

网络是不可靠的,客户端最后发送的ACK报文服务端可能没收到,服务端重新发送FIN报文,客户端发送ACK报文。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。

LISTEN - 侦听来自远方TCP端口的链接请求
SYN-SENT - 发送链接请求后等待匹配的链接请求
SYN-RECEIVED - 收到一个和发送一个请求等待确认的状态
ESTABLISHED - 代表一个打开的链接,可传输数据
FIN-WAIT-1 - 等待远程TCP链接终端请求,或先前连接中断请求的确认
FIN-WAIT-2 - 从远程TCP等待中断链接请求
CLOSE-WAIT - 等待从用户本地发来的中断请求
CLOSING - 等待远程TCP链接中断的确认
LAST-ACK - 等待原来发向远程TCP连接中断请求的确认
TIME-WAIT - 等待足够时间远程TCP收到连接中断请求的确认
CLOSED - 没有任何链接状态

总结

三次握手是为了客户端和服务端确认自己和对方收发报文能力正常,不能两次握手是因为第三次握手要确认客户端接收能力是否正常。

四次挥手,客户端和服务端都能主动发起,特别注意TIME-WAIT状态,不能立即变为CLOSED状态,是为了防止最后的ACK报文服务端没有收到,导致服务端重新发送FIN报文.

参考文章: