最近在复习计网,故总结本文,如有错误请评论区指出
文章目录
-
- TCP三次握手:建立可靠连接(核心目的:同步序列号,确认双方收发能力)
-
- 三次握手完整流程
-
- 第一步:客户端 → 服务器(SYN=1,seq=x)
- 第二步:服务器 → 客户端(SYN=1,ACK=1,seq=y,ack=x+1)
- 第三步:客户端 → 服务器(ACK=1,seq=x+1,ack=y+1)
- 为什么是三次握手,不是两次?
- TCP四次挥手:断开可靠连接(核心目的:确保双方数据都已传输完成,优雅释放资源)
-
- 四次挥手完整流程
-
- 第一步:客户端 → 服务器(FIN=1,seq=u)
- 第二步:服务器 → 客户端(ACK=1,seq=v,ack=u+1)
- 第三步:服务器 → 客户端(FIN=1,ACK=1,seq=w,ack=u+1)
- 第四步:客户端 → 服务器(ACK=1,seq=u+1,ack=w+1)
- 为什么是四次挥手,不是三次?
TCP三次握手:建立可靠连接(核心目的:同步序列号,确认双方收发能力)
三次握手的核心是双向确认:客户端和服务器都要确认"自己能发、也能收",避免出现"我能发但收不到你消息""你能收但发不出消息"的情况,最终建立稳定的连接。
先明确两个关键概念:
-
SYN:同步序列号,用于发起连接,告诉对方"我要开始建立连接了,我的初始序列号是X";
-
ACK:确认应答,用于确认收到对方的消息,告诉对方"我收到你的消息了,下一次你可以发序列号为Y的消息"。
补充:序列号(seq)是TCP可靠传输的关键,用于标识每一个字节的数据,避免数据丢失、重复、乱序------每发送一个字节,序列号就加1,接收方通过序列号确认数据是否完整。
三次握手完整流程
第一步:客户端 → 服务器(SYN=1,seq=x)
客户端主动向服务器发送连接请求报文,核心信息:SYN=1(表示发起连接),初始序列号seq=x(x是随机生成的一个数字,比如1000)。
目的:告诉服务器"我想和你建立连接,我的初始序列号是x,你可以开始准备接收我的数据了"。
此时,客户端状态:SYN-SENT(同步已发送,等待服务器确认)。
第二步:服务器 → 客户端(SYN=1,ACK=1,seq=y,ack=x+1)
服务器收到客户端的连接请求后,会回复一个确认+同步报文,核心信息:
-
ACK=1(表示确认收到客户端的SYN请求);
-
ack=x+1(表示"我已经收到你序列号为x的消息,下一次请你发送x+1及以后的消息");
-
SYN=1(表示服务器也向客户端发起同步,告诉客户端"我也准备好和你建立连接了");
-
seq=y(服务器的初始序列号,也是随机生成的,比如2000)。
目的:双向确认的关键一步------既确认自己收到了客户端的请求,也告诉客户端"我能发消息,我的初始序列号是y,你也准备接收我的数据"。
此时,服务器状态:SYN-RCVD(同步已接收,等待客户端最终确认)。
第三步:客户端 → 服务器(ACK=1,seq=x+1,ack=y+1)
客户端收到服务器的回复后,再向服务器发送一个最终确认报文,核心信息:
-
ACK=1(确认收到服务器的SYN+ACK报文);
-
ack=y+1(表示"我已经收到你序列号为y的消息,下一次请你发送y+1及以后的消息");
-
seq=x+1(客户端的下一个序列号,承接第一步的x,说明客户端已经准备好发送数据)。
目的:告诉服务器"我已经收到你的确认和同步,我这边也完全准备好,连接可以正式建立了"。
此时,客户端状态:ESTABLISHED (连接已建立,可开始传输数据);服务器收到该报文后,状态也变为ESTABLISHED,双方正式进入数据传输阶段。

为什么是三次握手,不是两次?
核心原因:避免"失效的连接请求"被服务器误判,导致资源浪费,同时确保双方收发能力都正常。
举个例子:客户端发送的第一个连接请求(SYN=x),因为网络延迟,过了很久才到达服务器------此时客户端已经超时重发了新的请求,并且和服务器建立了连接、传输完数据、断开了连接。而这个延迟的请求到达服务器后,服务器会误以为是客户端新的请求,若只有两次握手,服务器会直接发送SYN+ACK,然后进入连接状态,等待客户端发送数据,但客户端根本没有新的请求,不会回复,服务器会一直占用资源,造成浪费。
三次握手的第三次,就是客户端对服务器的SYN+ACK进行确认,确保双方都知道"对方能收能发",避免上述问题。
TCP四次挥手:断开可靠连接(核心目的:确保双方数据都已传输完成,优雅释放资源)
四次挥手的核心是双向释放:客户端和服务器都要确认"自己的数据已经全部发送完毕,也收到了对方的所有数据",才能彻底断开连接,避免数据丢失(比如服务器还在发数据,客户端突然断开,会导致数据丢失)。
补充:断开连接的发起方可以是客户端,也可以是服务器(比如客户端主动关闭浏览器,发起断开请求;或者服务器主动关闭连接),这里以「客户端主动发起断开」为例,拆解流程。
先明确个关键概念:FIN(结束标志),用于发起断开连接,告诉对方"我已经没有数据要发送了,准备断开连接"。
四次挥手完整流程
第一步:客户端 → 服务器(FIN=1,seq=u)
客户端数据传输完成后,主动向服务器发送断开连接请求报文,核心信息:FIN=1(表示发起断开连接),seq=u(u是客户端当前的序列号,即最后一次发送数据的序列号+1)。
目的:告诉服务器"我这边已经没有数据要发送了,你可以准备接收我最后的确认,然后我们断开连接"。
此时,客户端状态:FIN-WAIT-1(终止等待1,等待服务器确认)。
第二步:服务器 → 客户端(ACK=1,seq=v,ack=u+1)
服务器收到客户端的断开请求后,先回复一个确认报文,核心信息:ACK=1(确认收到客户端的FIN请求),ack=u+1(表示"我已经收到你所有的数据,你可以放心"),seq=v(服务器当前的序列号)。
目的:告诉客户端"我收到你要断开的请求了,但我这边可能还有数据没发送完,你先等一等,我发完数据就跟你断开"。
注意:这一步只是确认"收到断开请求",不是真正断开连接,服务器此时还可能在向客户端发送剩余数据。
此时,客户端状态:FIN-WAIT-2 (终止等待2,等待服务器发送自己的断开请求);服务器状态:CLOSE-WAIT(关闭等待,正在发送剩余数据)。
第三步:服务器 → 客户端(FIN=1,ACK=1,seq=w,ack=u+1)
服务器发送完所有剩余数据后,向客户端发送断开连接请求报文,核心信息:FIN=1(表示服务器也没有数据要发送了,准备断开连接),ACK=1(再次确认),seq=w(服务器最后一次发送数据的序列号+1),ack=u+1(和第二步的ack一致,再次确认收到客户端所有数据)。
目的:告诉客户端"我这边也没有数据要发送了,我们可以正式断开连接了"。
此时,服务器状态:LAST-ACK(最后确认,等待客户端的最终确认)。
第四步:客户端 → 服务器(ACK=1,seq=u+1,ack=w+1)
客户端收到服务器的FIN请求后,回复一个最终确认报文,核心信息:ACK=1(确认收到服务器的FIN请求),ack=w+1(表示"我收到你所有的数据了,你可以放心断开"),seq=u+1(客户端当前的序列号)。
目的:告诉服务器"我已经收到你要断开的请求,所有数据都已接收完毕,我们可以彻底断开连接了"。
此时,客户端状态:TIME-WAIT (时间等待,等待2MSL后彻底关闭);服务器收到该报文后,状态变为CLOSED(已关闭)。
补充:客户端的TIME-WAIT状态(等待2倍的最大报文段寿命),是为了确保服务器能收到客户端的最终确认------如果服务器没收到,会重发FIN请求,客户端在TIME-WAIT期间能再次回复,避免服务器一直等待。

为什么是四次挥手,不是三次?
核心原因:服务器收到客户端的FIN请求后,可能还有未发送完的数据,无法立即发送FIN请求,需要先回复ACK确认,等数据发送完毕后,再发送FIN请求,因此需要分两步,无法和ACK合并。
简单说:三次握手时,服务器的SYN和ACK可以合并发送(第二步),因为服务器不需要准备数据,收到请求后可以立即同步;但四次挥手时,服务器收到FIN后,可能还有数据要处理,只能先确认(ACK),再发送FIN,因此必须分两步,形成四次挥手。