网络编程(2) —— 三次握手与四次挥手、半连接状态、2MSL

文章详细解释了TCP协议中建立连接的三次握手过程和终止连接的四次挥手过程,包括每个阶段的目的和防止丢包、资源浪费的机制。三次握手确保双方的发送和接收能力,而四次挥手则允许双方有序地关闭连接,避免数据丢失。此外,提到了2MSL的作用和保活计时器的概念。
摘要由CSDN通过智能技术生成

一、三次握手

什么是三次握手?

        手机能够使用联网功能是因为手机底层实现了 TCP / IP 协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。

TCP共有6个标志位,常见的:

标志位含义
SYN(synchronous)建立连接
ACK(acknowledgement)响应确认
FIN(finish)结束
RST(reset)重置

建立起一个TCP连接需要经过“三次握手”

三次握手图解

在这里插入图片描述

 在这里插入图片描述

 2、为什么TCP连接的时候是3次?2次不可以吗?


因为需要考虑连接时丢包的问题,如果只握手2次,第二次握手时如果服务端发给客户端的确认报文段丢失,此时服务端已经准备好了收发数(可以理解服务端已经连接成功)据,而客户端一直没收到服务端的确认报文,所以客户端就不知道服务端是否已经准备好了(可以理解为客户端未连接成功),这种情况下客户端不会给服务端发数据,也会忽略服务端发过来的数据
如果是三次握手,即便发生丢包也不会有问题,比如如果第三次握手客户端发的确认ack报文丢失,服务端在一段时间内没有收到确认ack报文的话就会重新进行第二次握手,也就是服务端会重发SYN报文段,客户端收到重发的报文段后会再次给服务端发送确认ack报文。


因为客户端和服务端,这两端都需要确定对方的收发能力都是可以的!

客户端 --------------------------- 服务端
客发----------------------------客发、服接 (第一次)
客接、服发、服接------------- 服发 (第二次)
客接 (第三次)

仔细看我上面的简易列表,分别代表每一次握手客户端和服务端对双方收发能力的了解程度。
第一次客户端发送,那么客户端就知道了客户端的发送是好的,服务端收到发送,就知道了客户端的发送是好的,自己的接收是好的;然后第二次服务端返回信息,服务端就知道自己发送是好的,客户端收到信息就知道自己的接收是好的,服务端的发送是好的,同时自己上次发的信息返回来了,说明也知道了服务端的接收是好的。
重点来了!服务端还不知道客户端的接收怎么样啊!怎么办?客户端再发一次!

1、三次握手才可以阻止历史重复连接的初始化(主要原因)

1、客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接;
2、如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接:
如果是历史连接(序列号过期或超时),则第三次握手发送的报文是 RST 报文,以此中止历史
连接;


2、三次握手才可以同步双方的初始序列号

当客户端发送携带「初始序列号」的 SYN报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。


3、三次握手才可以避免资源浪费

如果只有「两次握手」,当客户端的 SYN 请求连接在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN ,由于没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的ACK 确认信号,所以每收到一个 SYN 就只能先主动建立一个连接,这会造成什么情况呢?

如果客户端的 SYN 阻塞了,重复发送多次 SYN 报文,那么服务器在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费
 

1.当客户端发起SYN链接时,过去因为网路阻塞发起的旧的链接可能先于新的链接到达服务器端,服务器端会根据旧的链接返回一个旧的ack应答。通过第三次握手,客户端发现该应答不是最新,就会发出RST报文给服务器,表示中止链接。如果没有第三次握手,便无法与客户端最新请求生成链接。
2.根据上图,客户端发起链接会有一个序列号,服务器会根据该序列号生成ack应答;同时服务器也产生一个序列号,要求客户端也需要根据服务器的序列号产生相应的ack应答。这样两边的初始序列号就可以同步。否则会造成序列混乱。
3.由于网络阻塞,客户端前期发起了多次SYN请求都被阻塞

三次握手过程解析:

(1)第一次握手

客户端发送 SYN 包( syn = j )到服务器,并进入 SYN_SEND 状态,等待服务器确认。

j 是一个随机数,通过看服务器返回的 j + 1 是否正确,判断第一次握手服务器是否正确响应。

(2)第二次握手

服务器确认客户的 SYN 包,同时发送 ACK 包( ack = j + 1 )作为回应;

自己也发送一个 SYN 包( syn = k ),共两个包,此时服务器进入 SYN_RECV 状态;

k 也是一个随机数,也是用于看客户端返回的 k+1 是否正确,判断第二次握手客户端是否正确响应。

(3)第三次握手

客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK ( ack = k + 1 ),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手。

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

二、四次挥手

什么是四次挥手?

        四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在 socket 编程中,这一过程由客户端或服务端任一方执行close来触发。

四次挥手图解

在这里插入图片描述

 在这里插入图片描述

四次挥手过程解析:

(1)第一次挥手

客户端发送一个 FIN = M,用来关闭客户端到服务器端的数据传送,客户端进入 FIN_WAIT_1状态 。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。

(2)第二次挥手(半连接)

服务器端收到 FIN 后,先发送 ack = M + 1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态(半连接状态),继续等待服务器端的FIN报文

 (3)第三次挥手

当服务器端确定数据已发送完成,则向客户端发送 FIN = N 报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。

(4)第四次挥手

客户端收到 FIN = N 报文后,就知道可以关闭连接了。

但是他还是不相信网络,怕服务器端不知道要关闭,所以发送 ack = N + 1后进入TIME_WAIT状态,如果 Server 端没有收到 ACK 则可以重传。服务器端收到ACK后,就知道可以断开连接了。

客户端等待了 2MSL 后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。

三、2MSL作用

在这里插入图片描述

  • 假设客户端最后一个确认报文段丢失,如果没有2MSL等待时间,那么服务端一直发送超时重发报文,最终无法进入CLOSED状态

  • 2MSL时长可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的TCP连接中不会出现旧连接中的报文段

四、 常见问题

1、为什么连接是三次握手,关闭却要四次挥手(半连接)?

建立连接时,ACK 和 SYN 可以放在一个报文里来发送。

而关闭连接时,被动关闭方可能还需要发送一些数据,再发送 FIN 报文表示同意现在可以关闭连接了,所以它这里的 ACK报文 和 FIN报文 多数情况下都是分开发送的。

说得尽可能具体一些就是

 客户端发送FIN关闭报文,但是服务端仍在给他发送数据不能马上停止服务端先给出ACK报文回应(你的请求我收到了,但要等我发完数据才能关闭哦)。当服务端发送完毕后,再发送FIN报文请求关闭,所以这两个报文不能同时发送,故有了四次挥手。

 如果把三次握手改为仅需要两次握手,可能发生死锁。 

2、连接中途客户端突然故障怎么办(保活计时器、探测报文段、心跳包)?

在这里插入图片描述

 TCP还设计有一个①保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。

        服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个②探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
 

另外的:如果客户端没有数据发送,又不想断开的话还要发③心跳包,心跳包这个数据没用,只是告诉服务器我客户端还在【长连接】

为什么客户端发出第四次挥手的确认报文后要等2MSL的时间才能释放TCP连接?

这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认ack报文就会重发第三次挥手的报文,这样报文一去一回最长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。

客户端和服务器端那一个最先关闭连接?

注意看图,客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。

补充问题

  • 📝TCP的三次握手一定能保证传输可靠吗?不能
  • 三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。
  • 世界上不存在完全可靠的通信协议。从通信时间成本空间成本以及可靠度来讲,选择了“三次握手”作为点对点通信的一般规则

粘贴别人的过程来强调一下序列号的问题:

比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。

第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,序列号等于初始化序列号+发送的字节数+1,其中的1是建立连接时占的一个序列号)。
(需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。)

第二次挥手:服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102、序列号seq=2300(300+2000)(这里没有+1)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。(忙完手头的活)

第三次挥手:服务端将最后数据**(比如50个字节)**发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。

第四次挥手:客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。

四次挥手时因为中间传输了数据,所以序列号出现了变化,而在三次握手时没有考虑数据,所以没有加数据的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值