✨✨✨励志成为超级技术宅 ✨✨✨
TCP的三次握手在笔试和面试中经常考察,非常重要,那么大家有没有思考过为什么是三次握手,俩次握手行不行呢?四次握手行不行呢?如果大家有疑问或者不是很理解,那么这篇博客有图有讲解,一定能帮助大家思考,希望大家能看看了( つ•̀ω•́)つ。
一.知识铺垫
首先tcp协议的格式如下:
这里我们先了解32位序号和32位确认序号。假设我们是客户端,32位序号就像学生id唯一标识标识一段传输的TCP报文, 32位确认序号就是收到服务端TCP报文时,将服务端的32位序号+1作为我们客户端的32确认序号发送给服务器。也就是我们端的32位确认序号等于对端的32位序号+1。
为什么会有确认序号产生呢?这是为了确保消息能被收到。举个例子,在生活中,辅导员为了确保重要的消息被同学知道, 会在班群通知,XXX重要消息,收到请回复。只要有同学对这条消息回复,就代表消息收到了,这时老师和同学就类似于服务器和客户端,服务器和客户端确保的通信被收到的机制其实也就是收到请回复。我们将收到消息的32位序号+1作为32位确认序号放入消息中,就是我们对这条32位序号消息的回复。
通过32位序号和32位确认序号结合,我们就能在发送消息的同时进行回复。 32位序号表示发送的消息序号,32确认序号就表示对哪条消息的收到确认回复。当发送需求和回复确认需求同时都存在时,俩个序号就会添加上对应的值,这就是捎带应答(可以理解为因为要发送消息就顺便应答一下的意思)。TCP三次握手的第二次握手就是捎带应答,因为在同一时间内具有发送需求(建立连接)和确认需求(对第一次握手应答)。
二.回顾三次握手流程
SYN和ACK是TCP六位标志位中的俩位,当标志位置1表示有效。我们先来讲解含义。
SYN是“Synchronize”(同步)的缩写,用来请求建立连接。ACK是“Acknowledgment”(确认)的缩写,ACK报文的主要作用是确认接收方已经成功接收了发送方发送的数据段 。
在三次握手中,当客户端以及服务端发送含有SYN标志位请求时就表示要建立连接,发送ACK报文就表示对另一方连接请求的确认。另外,双方发送的含有SYN的消息的32位序号是随机的,对于每一次的ack请求都是不同的。
那么我们来概括一下三次请求的简要流程:
1.第一次握手(SYN):
- 客户端(Client):发送一个带有SYN(同步序列编号)标志位的TCP报文段给服务器,请求建立连接。此时,客户端进入SYN_SEND状态。
- 报文内容:SYN=1,初始序列号seq=x(客户端随机的初始序列号)。
2.第二次握手 (SYN+ACK):
- 服务器(Server):收到客户端的SYN报文段后,确认SYN报文段有效,并回复一个带有SYN和ACK(确认)标志位的TCP报文段给客户端,表示同意建立连接。此时,服务器进入SYN_RCVD状态。
- 报文内容:SYN=1,ACK=1,确认号ack=x+1(表示收到了客户端的序列号x),初始序列号seq=y(服务器随机的初始序列号)。
3.第三次握手(ACK):
- 客户端(Client):收到服务器的SYN+ACK报文段后,确认该报文段有效,并向服务器发送一个带有ACK标志位的TCP报文段,表示已经收到了服务器的SYN报文段。此时,客户端和服务器都进入ESTABLISHED(已建立连接)状态,可以开始传输数据。
- 报文内容:ACK=1,确认号ack=y+1(表示收到了服务器的序列号y)。
了解上面的知识我们也就能探索为什么是三次握手了。
三.为什么不是俩次握手
1.确保双方的通信能力
首先我们要怎么才能确定一端到对端的通信能力呢?答案是请求被回复。请求被回复就说明对方成功接收到了消息,没有回复可能是对方没有收到或者对方发送消息的通路有问题
当客户端发送建立连接的请求SYN,之后如果客户端收到了服务器回复了SYN和ACK的消息。此时作为客户端我们就能确定客户端到服务器的连接是畅通的,因为我们收到了回复,而回复就代表我们的消息被对端成功接收,客户端到服务器通信是畅通的。
而作为服务端,当我们对客户端的连接请求,回复SYN和ACK消息,如果要确保服务器到客户端通信畅通,也必须需要收到回复,这就是第三次握手的意义,客户端发送ACK消息对服务端的的连接请求回复确认消息ACK,当此时服务器收到消息了,就代表服务器到客户端通信是正常的,即三次握手确认后了双方的通信能力
始终要记住只有我们的消息被回复才能保证我们的消息被收到。
总体来说只要俩边的SYN请求都能接收到ACK回复,就表明俩边的SYN请求都已经被对端收到,双方通信就是正常的。
那么为什么不能是俩次握手,俩次握手双方不是也已经进行互相通信了吗?此时为什么还不能确保双方的通信能力。
答案是此时虽然进行了互相通信,但是只有客户端的连接请求被确认,而服务器的请求还没有进行回应,俩次握手后,客户端如果收到回应,是能确保自己到服务端的通路和服务端到自己的通路是正常的,但是此时作为服务器,我们并不能确认我们的SYN和ACK消息被收到,只有收到回应才能确保我们的消息被正确送到对方,才能确保服务器到客户端的通路是畅通的。
因此完成俩次握手客户端能确认自己到服务器的通信正常,服务器无法确保自己到客户端通信正常。
我们在从另外一个角度看,对于俩次握手,如果第二次握手失败,即服务器发送的SYN报文因为网络等原因没有送达,服务器就会认为连接建立,进行监听并发送数据,而客户端因为服务器报文丢失,根本不会建立连接发送消息,此时服务器就会监听和对不存在的连接发消息,浪费资源。
而对于三次握手,第二次握手失败,服务器也不会建立连接,不会浪费资源,甚至因为网络变化第三次握手失败,此时客户端已经建立连接,但是服务器依旧不会建立连接,这时服务器的三次任何一次握手失败的代价都不用服务器承担,第三次失败也是客户端承担代价。能减少服务器负担。
2.防止历史报文的干扰
历史报文的干扰的情况是指因为网络延迟等问题服务器第一次发送的SYN报文被阻塞在网络中,此时服务器会再次发送第二次SYN报文,第二次报文成功发送,如果此时第一次的SYN报文之后又发送到服务器又会怎样?
我们就来讲讲三次握手是怎么防止历史报文的干扰,首先每次SYN报文的32序列号是随机的,我们假设第一次阻塞的SYN报文32位初始序列号是100(随便写几位),第二次成功送达的序列号是200,此时服务器回应ACK和SYN报文,此时32位确认序号是201,此时如果阻塞报文在第二次成功送达的报文之后到来,服务器不能区分新旧(因为初始序列号是随机的,且此时连接为建立),同样会进行回应,确认序列号101。这时客户端会收到俩份ACK和SYN的报文,一份确认序列化101,一份201,服务器是能记住自己最新的初始序列号200的,因此201符和预期,客户端会对201的报文进行一份回应,101不符合客户端直接丢弃。此时客户端和服务器各自只建立了一份连接,服务器虽然多建立一个syn_rcvd状态但是并不会太浪费资源。
我们再来看看俩次连接为什么不能防止历史连接干扰
首先假设只有俩次握手,在服务器对客户端的SYN报文进行回复后,那么服务器就会认为连接建立了(因为俩次握手的就要建立连接)。因此服务器收到俩次SYN请求会分别添加2个连接, 此时客户端由于上面同样的原因,会丢弃一份SYN和ACK报文,只会添加一个连接。
因此俩次握手不能防止历史连接干扰而三次握手可以。此外还有一种情况如果三次握手成功后,历史连接再次到来的情况,我询问了老师,因为五元组相同(源ip,目的ip,源端口,目的端口,协议类型),此时服务器会检查建立与对于客户端建立的连接,发现连接正常,对于历史连接就会直接丢弃,不过此时并不能很好体现为什么要三次握手了而不是俩次握手了。
四.为什么不是四次握手
通过上面的讲解我们能明白三次握手已经能很好完成建立连接的功能,对于为什么不是四次握手我们就能很好理解。
主要是为了避免资源浪费和协议设计的简洁性
在TCP连接建立的过程中,如果采用四次握手,将会增加通信的开销和延迟,降低连接建立的效率。 TCP协议的设计注重简洁性和高效性。三次握手的过程既能够确保连接的可靠性,又能够避免不必要的复杂性和开销。如果增加到四次握手,将会使协议变得更加复杂和冗余。
综上所述,TCP采用三次握手而不是四次握手,是在保证连接可靠性和通信效率之间的一种平衡选择。这种机制不仅简单可靠,而且能够有效地避免连接建立过程中的问题。
五.三次握手的意义
我们最后再来完全总结一次三次握手的意义(毕竟经常考):
1.确保双方的通信能力
2.防止历史报文的干扰
3.交换彼此的窗口大小(即接收缓冲区剩余空间)和初始化序列号(也可说是交换滑动窗口的头指针位置)
对于第三点如果不了解或者想要更好理解TCP协议的全部内容的话,可以看本人关于TCP协议的另外一篇博客 TCP 协议详解_tcp协议-CSDN博客。里面详细讲解了TCP的各种知识点,相信可以帮助你更好理解TCP全貌。
感觉有帮助的请点个赞,这真的很重要。٩(๑òωó๑)۶