谈谈对TCP三次握手,四次挥手的个人总结笔记

个人对TCP三次握手,四次挥手的详细理解

之前大三时候学习计算机网络时候虽然也接触了解过TCP三次握手和四次挥手,但是当时由于主要是面向考试原因,并没有很好理解其中含义,特别是一直搞不懂哪些发送的报文字段啥意思,看的表示一脸懵逼。这次当然自己花了点时间查阅了点资料和加上自己理解做了这个自认为通俗易懂的理解。

这是网络上一个标准的TCP三次握手的图示首先先说下那些客户端和服务端发送的报文字段含义:
SYN:(synchronous建立联机)
Seq:(Sequence number顺序号码)
Ack:(acknowledgement 确认)

第一次握手:客户端发送位码为SYN=1(为什么为1,本人理解可能协议中规定的SYN=1代表着建立联机请求意思吧),然后随机产生Seq number=1234567(注意:这个Seq数字的产生是随机的)的数据包到服务器,服务器由SYN=1知道,客户端要求建立联机;

第二次握手:服务器收到请求后要确认联机信息,向客户端发送Ack=(服务端发送的seq+1),SYN=1,并随机产生Seq=7654321(Seq数字是随机的,也可以不是7654321)的包;

第三次握手:客户端收到后检查Ack是否正确,即第一次发送的Seq+1,以及位码Ack是否为1,若正确,客户端会再发送Ack=(服务器的Seq+1),Ack=1,服务器收到后确认Seq值与Ack=1则连接建立成功。

通俗理解
客户端 为了跟服务端建立连接,先对服务端发送了一个SYN报文,这个报文可能协议中默认为1代表着向对方请求建立连接意思,然后在加上个Seq顺序号码,至于为啥要这个Seq顺序号码,是因为,Seq号码是随机产生的一个数字,方便后面客户端能确认服务端收到请求的一个验证标记,因为第二次握手时候,服务端发回的Ack确认码里面值就是第一次握手发送的顺序号码Seq的值+1,因为发送的Seq号码的随机性,所以因为错误而返回的确认码跟正确的顺序码很大几率不会一样(这里说大概率不会相同,但是也可能存在极小概率出错问题)。当服务端接收到客户端第一次握手请求来的建立联机报文SYN=1和随机顺序号Seq时候,将会返回同样一个SYN=1 (这里SYN=1意思是同样告诉客户端,我同意跟你建立连机,你是否同意跟我建立连机),Ack=Seq+1 (这个不用多说了吧,是让客户端知道服务器接收到了他之前发送的请求报文的一个表示符而已),然后再自己随机产生一个Seq=6666 顺序号(同理这个顺序号也是为了最后服务端确定客户端接收到了二次握手发送的连接请求的表示符而已)。最后也是叫做第三握手,就是客户端发送Ack=Seq+1确认报文(这个里面的Seq是第二次握手时候服务端随机产生的值,而不是客户端第一次产生的,这要分清楚),再产生一个Seq随机顺序号(至于这个Seq顺序号有啥用,说实话,如果后面服务器还要继续确认的话,就可以用这个Seq顺序号,不然其实没啥用,但是因为3次握手已经基本可以确定是否建立连接了,4次,5次,6次…循环下去也只是相当于递归循环而已,不会对建立连接,防止丢包产生太大帮助,所以3次握手就相当于完整循环一次并且效益最大化,这也是为什么建立连接只是3次握手而不是越多越好原因)。

接下来讲下4次挥手

注:图示是借用网路上我之前笔记保存的觉得比较好演示4次挥手的样图,出处我也忘了
FIN:(表示关闭连接字段)
其他字段上面写的三次握手已经讲诉了,这里不过多叙述了。

对于4次挥手,我觉得这个博主讲的挺好,所以用了他的解释:
假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,“告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息”。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,“告诉Client端,好了,我这边数据发完了,准备好关闭连接了”。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,“就知道可以断开连接了”。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!

原文链接:https://blog.csdn.net/qiandublog/article/details/53257292

通俗来讲:
4次挥手我看到很多博主的解释用的都是客户端首先发起断开连接的请求的例子,容易让人感觉为啥不能先是服务端请求断开呢?其实这样完全可以,服务端一样可以先发送断开连接请求,这样等于课本上4次挥手的顺序,前两次跟后两次调换了个位置而已,理解还是一样的。这里我还是拿上图普遍的样例来解释,即首先客户端发出断连请求,首先第一次挥手客户端发送FIN=1 报文(注意这个FIN=1只是个请求关闭连接的报文字段),随机产生一个Seq序列号。当服务端接受到了客户端发来的断连报文后,就会立马发送一个Ack=Seq+1确认报文和一个随机的Seq顺序号。(至于图上那个有ack=seq+1为什么还要重复发送一个ACK=1,我找了很多资料没见合理解释,有大佬知道可以留言指教一下,谢谢)。这个过程称为第二次挥手,第二次挥手只是服务端告诉客户端,我收到了你第一次发送来的请求,但是这个请求不一定是请求 关闭连接的报文,也可能是告诉服务器,让服务器等待客户端继续发送数据的等待报文也可能,所以服务器此时只能先回复一个收到请求,然后再根据第一次挥手的请求来决定怎样回复,假设第一次挥手请求是请求关闭连接,那么随后第三次挥手,就是服务端向客户端发送一个FIN=1请求关闭连接的报文,再加上Ack=Seq+1的确认报文,再加上随机的顺序号Seq给客户端。当客户端接收到断开连接报文后,随机发送Ack=Seq+1确认报文(这里的Seq是第三次挥手服务端发送的顺序号),加上随机的Seq顺序号。(这里我看到很多博主包括百度百科,发现很多人这里Seq序列号值都不一样,我也不确定哪个最可靠,但是要知道序列号最大意义就是随机,防止偶然,作为一种确认码一样,所以取值哪个影响不太大),当客户端发送完最后一个请求,也就是第四次挥手后,他会在2MSL后关闭连接,也默认服务端接受到请求断开连接了。

接下来大家可能会有几个问题,我刚开始看的时候也想过,我列举下:

1、要是三次握手和四次挥手中途丢包了怎么办?服务器或者客户端怎么确定对方是否收到报文?
对于这个问题,我看了一个博主解释,感觉解释很详细,我就不做过多叙述了。
四次挥手的正常发包和应答过程,我们已经简单了解了,接下来就继续看看,四次挥手过程中,出现的异常情况。

				**1. 断开连接的 FIN 包丢了。**
				我们前面一直强调过,如果一个包发出去,在一定时间内,只要没有收到对端的「ACK」回复,均认为这个包丢了,会触发超时重传机制。而不会关心到底是自己发的包丢了,还是对方的「ACK」丢了。
				所以在这里,如果客户端率先发的「FIN」包丢了,或者没有收到对端的「ACK」回复,则会触发超时重传,直到触发重传的次数,直接关闭连接。
				对于服务端而言,如果客户端发来的「FIN」没有收到,就没有任何感知。会在一段时间后,也关闭连接。
				
				2. 服务端第一次回复的 ACK 丢了。
				此时因为客户端没有收到「ACK」应答,会尝试重传之前的「FIN」请求,服务端收到后,又会立即再重传「ACK」。
				而此时服务端已经进入 CLOSED-WAIT 状态,开始做断开连接前的准备工作。当准备好之后,会回复「FIN,ACK」,注意这个消息是携带了之前「ACK」的响应序号的。
				只要这个消息没丢,客户端可以凭借「FIN,ACK」包中的响应序号,直接从 FIN-WAIT-1 状态,进入 TIME-WAIT 状态,开始长达 2MSL 的等待。

				3. 服务端发送的 FIN,ACK 丢了。
				服务端在超时后会重传,此时客户端有两种情况,要么处于 FIN-WAIT-2 状态(之前的 ACK 也丢了),会一直等待;要么处于 TIME-WAIT 状态,会等待 2MSL 时间。
				也就是说,在一小段时间内客户端还在,客户端在收到服务端发来的「FIN,ACK」包后,也会回复一个「ACK」应答,并做好自己的状态切换。
			
				4. 客户端最后回复的 ACK 丢了。
				客户端在回复「ACK」后,会进入 TIME-WAIT 状态,开始长达 2MSL 的等待,服务端因为没有收到「ACK」的回复,会重试一段时间,直到服务端重试超时后主动断开。
				或者等待新的客户端接入后,收到服务端重试的「FIN」消息后,回复「RST」消息,在收到「RST」消息后,复位服务端的状态。
				
				5. 客户端收到 ACK 后,服务端跑路了。
				客户端在收到「ACK」后,进入了 FIN-WAIT-2 状态,等待服务端发来的「FIN」包,而如果服务端跑路了,这个包永远都等不到。
				在 TCP 协议中,是没有对这个状态的处理机制的。但是协议不管,系统来凑,操作系统会接管这个状态,例如在 Linux 下,就可以通过 tcp_fin_timeout 参数,来对这个状态设定一个超时时间。
				需要注意的是,当超过 tcp_fin_timeout 的限制后,状态并不是切换到 TIME_WAIT,而是直接进入 CLOSED 状态。
				参考:《关于FIN_WAIT2》
		
		6. 客户端收到 ACK 后,客户端自己跑路了。
		客户端收到「ACK」后直接跑路,服务端后续在发送的「FIN,ACK」就没有接收端,也就不会得到回复,会不断的走 TCP 的超时重试的机制,此时服务端处于 LAST-ACK 状态。
		那就要分 2 种情况分析:
		    在超过一定时间后,服务端主动断开。
		    收到「RST」后,主动断开连接。
		「RST」消息是一种重置消息,表示当前错误了,应该回到初始的状态。如果客户端跑路后有新的客户端接入,会在此发送「SYN」以期望建立连接,此时这个「SYN」将被忽略,并直接回复「FIN,ACK」消息,新客户端在收到「FIN」消息后是不会认的,并且会回复一个「RST」消息。

原文链接:https://blog.csdn.net/plokmju88/article/details/104305897

2、三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据。为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。

说到这,大家有没有想过,如果第一次握手已经成功了,服务器返回Ack+Seq报文回去,这时候如果客户端不给确认回复,那服务器会干嘛呢?服务器会认为是不是客户端没收到请求报文,于是会再次重发确认请求,而这个确认请求一般在规定次数下来总花费时间大概将近1分多钟,(此时处于所谓半连接状态)这样的话,如果只是偶尔几个丢包,服务器可以快速的处理,如果大量的人为恶意发送握手请求SYN到服务器,而不给服务器返回确认报文,那么服务器不断给每个请求重发,这样消耗了大量CPU资源,也就容易导致服务器瘫痪,形成DOS(denial of service)攻击,这种攻击的方式也就是大家熟知的SYN Flood.

3、为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
两个存在的理由:
1、无法保证最后发送的ACK报文会一定被对方收到,所以需要重发可能丢失的ACK报文。
2、关闭链接一段时间后可能会在相同的IP地址和端口建立新的连接,为了防止旧连接的重复分组在新连接已经终止后再现。2MSL足以让分组最多存活msl秒被丢弃。

4、为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值