分析三次握手和四次挥手之前带着如下问题进行阅读,收获会更大
- 请画出三次握手和四次挥手的示意图
- 为什么连接的时候是三次握手?
- 什么是半连接队列?
- ISN(Initial Sequence Number)是固定的吗?
- 三次握手过程中可以携带数据吗?
- 如果第三次握手丢失了,客户端服务端会如何处理?
- SYN攻击是什么?
- 挥手为什么需要四次?
- 四次挥手释放连接时,等待2MSL的意义?
1.什么是三次握手
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。
进行三次握手:
第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN。此时客户端处于 SYN_SENT 状态。
首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 的状态。
在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
在socket编程中,客户端执行connect()时,将触发三次握手。
1.1 为什么需要三次握手,两次不行吗?
在计算机网络中,TCP 协议通过 “三次握手” 建立连接,这一设计并非偶然,而是为解决两次握手存在的根本性缺陷。以下从三次握手的流程、两次握手的不足、实际场景风险等方面展开分析: 一、三次握手的核心流程与目的
1. 三次握手的具体步骤
第一次握手(客户端→服务器)
客户端发送带有SYN(同步序列号)标志的数据包,请求建立连接,并携带初始序列号Seq=X。此时客户端进入SYN_SENT状态。
第二次握手(服务器→客户端) 服务器收到请求后,返回SYN+ACK数据包: SYN=1表示确认同步请求; ACK=1表示确认收到客户端的 SYN,附带确认号Ack=X+1; 服务器同时发送自己的初始序列号Seq=Y。此时服务器进入SYN_RCVD状态。
第三次握手(客户端→服务器) 客户端收到服务器的SYN+ACK后,发送ACK数据包: ACK=1确认收到服务器的 SYN,确认号Ack=Y+1; 自身序列号Seq=X+1(基于第一次握手的序列号递增)。 至此,双方进入ESTABLISHED状态,连接正式建立。
2. 三次握手的核心目的
双向确认通信能力:客户端确认服务器的发送与接收能力,服务器确认客户端的发送与接收能力。 初始化序列号:双方协商并确认初始序列号,为后续数据传输的可靠性(如排序、重传)奠定基础。
二、两次握手的致命缺陷:无法解决 “半连接” 与 “旧连接复用” 问题
1. 缺陷一:客户端接收能力无法验证(导致 “半连接”)
若仅两次握手: 客户端发SYN(Seq=X),服务器回ACK(Ack=X+1,Seq=Y),服务器认为连接已建立,开始分配资源(如创建套接字、分配缓冲区)。
风险:若客户端未收到服务器的ACK(如网络故障),客户端不会认为连接建立,而服务器已处于等待状态,导致服务器资源浪费(“半连接”)。
三次握手的解决方案:第三次握手时,客户端发送ACK确认收到服务器的SYN+ACK,服务器只有在收到该ACK后才正式建立连接,避免资源浪费。
2. 缺陷二:无法拒绝 “旧连接请求”(导致连接混乱) 假设网络中存在旧的SYN数据包(如客户端之前发送的连接请求因网络延迟滞留): 若两次握手:旧SYN到达服务器,服务器返回ACK,并认为连接建立,但客户端此时可能已发起新连接或无连接需求,导致服务器错误分配资源。
三次握手的解决方案:客户端收到服务器针对旧SYN的SYN+ACK时,发现序列号与当前期望的不一致,会拒绝发送第三次ACK,服务器因未收到ACK而超时关闭连接,避免旧连接干扰。
三、实际场景举例:两次握手的风险具象化
场景:客户端频繁重启或网络延迟较高
两次握手情况: 客户端第一次发送SYN1(Seq=100),因网络延迟未到达服务器,客户端超时后重发SYN2(Seq=200),服务器收到SYN2后返回ACK(Ack=201,Seq=300),连接建立。 若此时滞留的SYN1突然到达服务器,服务器会误认为是新请求,返回ACK(Ack=101,Seq=400),并等待客户端确认。但客户端当前连接的序列号是 200,不会响应该ACK,导致服务器持续等待,浪费资源。
三次握手情况: 服务器收到旧SYN1后返回SYN+ACK(Ack=101,Seq=400),客户端发现期望的序列号是 200+1=201,而非 101,因此拒绝发送第三次ACK,服务器超时后关闭错误连接。
四、总结:三次握手的本质 ——“可靠连接” 的最小代价方案
TCP 作为面向连接的可靠协议,其核心需求是:
确认双方的发送与接收能力; 避免旧连接干扰; 防止资源无效占用。 两次握手无法同时满足上述需求,而三次握手通过 “请求 - 确认 - 再确认” 的机制,以最小的通信开销(三次数据包交互)实现了连接的可靠性。这一设计是计算机网络中 “性能” 与 “可靠性” 平衡的经典案例。
1.2 什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
这里在补充一点关于SYN-ACK 重传次数的问题:
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
1.3 ISN(Initial Sequence Number)是固定的吗?
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
1.4 三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
1.5 SYN攻击是什么?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstat 命令来检测 SYN 攻击。
常见的防御 SYN 攻击的方法有如下几种:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
2.什么是四次挥手
2.1四次挥手的概念
四次挥手(Four-Way Handshake)是TCP协议中用于终止连接的过程。当通信双方需要关闭TCP连接时,需要通过四次数据包交换来确保双方都能安全地释放资源。这一机制保证了连接的可靠关闭,避免数据丢失或资源泄漏。
2.2四次挥手的步骤
第一次挥手
主动关闭方(通常为客户端)发送FIN(Finish)报文,表示不再发送数据,但仍可接收数据。此时主动方进入FIN_WAIT_1状态。
第二次挥手
被动关闭方(通常为服务器)收到FIN后,发送ACK(Acknowledgment)报文作为确认。此时被动方进入CLOSE_WAIT状态,主动方收到ACK后进入FIN_WAIT_2状态。
第三次挥手
被动关闭方处理完剩余数据后,发送自己的FIN报文,表示准备关闭连接。此时被动方进入LAST_ACK状态。
第四次挥手
主动关闭方收到FIN后,发送ACK报文确认,并进入TIME_WAIT状态。被动方收到ACK后直接关闭连接,而主动方需等待2MSL(Maximum Segment Lifetime)时间后关闭连接,确保最后一个ACK到达对方。

2.3 挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
2.4 2MSL等待状态
TIME_WAIT状态也成为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。
对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。
这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口(客户的IP地址和端口号,服务器的IP地址和端口号)不能再被使用。这个连接只能在2MSL结束后才能再被使用。
2.5 四次挥手释放连接时,等待2MSL的意义?
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
两个理由:
保证客户端发送的最后一个ACK报文段能够到达服务端。
这个ACK报文段有可能丢失,使得处于LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认,服务端超时重传FIN+ACK报文段,而客户端能在2MSL时间内收到这个重传的FIN+ACK报文段,接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务端都进入到CLOSED状态,若客户端在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到服务端重传的FIN+ACK报文段,所以不会再发送一次确认报文段,则服务端无法正常进入到CLOSED状态。
防止“已失效的连接请求报文段”出现在本连接中。
客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。
2.6 为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?
理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。

1347

被折叠的 条评论
为什么被折叠?



