三次握手和四次挥手是老生常谈的面试题了,面试官会根据这个问题衍生出来一堆问题,本文将根据这个问题讨论下衍生出的一些问题。看完这篇应该会对三次握手和四次挥手有一个比较详细和全面的了解。
文章目录
- 一、三次握手详解
- 二、四次挥手详解
- 三、常见衍生问题
- 1、为什么需要三次握手而不是两次或者四次?
- 2、在三次握手中,SYN和ACK的作用是什么?
- 3、三次握手过程中可以携带数据吗?
- 4、如果第三次握手丢失了,客户端和服务端会如何处理?
- 5、为什么需要四次挥手来关闭一个TCP连接?
- 6、在四次挥手中,为什么客户端在发送FIN之后还要等待一段时间(2MSL)才进入CLOSED状态?
- 7、如果在四次挥手中,客户端发送的ACK丢失了,会发生什么?
- 8、TCP连接中的半连接队列和全连接队列是什么?
- 9、TCP连接中ISN(Initial Sequence Number)是什么?
- 10、SYN攻击是什么?如何防范SYN攻击?
- 11、为什么TCP连接建立需要发送序列号?
- 12、在TCP通信中,如果一方突然崩溃,另一方如何知道?
三次握手和四次挥手是TCP协议中建立和断开连接时的过程,它们的主要作用是确保通信双方的连接建立可靠和断开时数据能够完全传输。三次握手和四次挥手是TCP协议中保证连接建立和断开可靠性的重要机制。
一、三次握手详解
三次握手是指建立TCP连接协议时,需要在客户端和服务器之间发送三个数据包。这三次握手的主要目的是为了确认双方的接收能力和发送能力是否正常,并同步连接双方的序列号和确认号,交换TCP窗口大小信息,以便为后续的可靠数据传输做准备。
具体过程由下图和文字一起解析:
- 握手时准备:刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。
- 第一次握手:客户端状态变化为
SYN_SENT
状态,意味着准备TCP报文段发送,该报文段中不包含应用层数据,但是在报文段的首部中的一个标志位(即SYN比特
)设置为1,因此,这个报文段也被称为SYN报文段。另外,客户端会随机选择一个初始序号x
,并将此编号放置于SYN报文段的序号字段中。 该报文段会被封装在一个IP数据报中,并发送给服务器。 - 第二次握手:包含SYN报文段的IP数据报到达服务器后,服务器会从该数据报中获取到TCP SYN报文段,为该TCP连接分配TCP缓存和变量,并向该客户TCP发送允许连接的报文段(也称
SYNACK
报文段)。这个允许连接的报文段也不含应用层数据。 - 但是报文段首部有三个重要的信息。首先,
SYN比特
置为1。其次,该TCP报文段的首部的确认号字段ACK
被置为x + 1
。最后服务器选择自己的初始序号seq = y
添加到首部的序号字段中。 - 第三次握手:客户端在收到服务器的
SYNACK
报文段后,客户端也要给该连接分配缓存和变量。客户主机则向服务器发送另外一个报文段,是对SYNACK
报文段进行确认。ack
设置为y + 1
,这是对SYNACK
报文段的确认,同时因为是第二次连接,设置seq = x + 1
,因为已经确认建立连接,设置SYN比特 = 0
。
完成这三个步骤,客户和服务器主机就可以相互发送带有数据的报文段。在往后的每一个报文段中的SYN比特 = 0
。
上述的专有名词介绍:
- 报文段:在计算机领域中,报文段(segment)特指在TCP/IP协议网络传输过程中,起着路由导航、查询各个网络路由网段、IP地址、交换协议等功能的IP数据包。它是传输层组成报文的每个分组,起始点和目的地都是传输层的信息单元。在面向连接(TCP)的数据传输中,传输层的分组被称为报文段。
- 此外,HTTP应用程序之间发送的数据块也被定义为报文。具体来说,HTTP请求报文由请求行、请求头部、空行和请求正文4个部分组成。而HTTP响应报文则包括状态行、响应头部、空行和响应正文4个部分组成。
- 比特:在计算机科学中,比特(bit)是信息量的基本单位,也是计算机二进制编码系统中表示信息的最小单位。比特由二进制数0或1来表示,通常用于表示计算机中的数据。例如,我们常说的存储容量单位(如字节、千字节、兆字节等)都是以比特为基础的。具体来说:1 字节(Byte) = 8 比特(bit)。
二、四次挥手详解
四次挥手则是指终止TCP连接协议时,需要在客户端和服务器之间发送四个数据包。这个过程确保了在断开连接时,双方都能够完整地传输所有数据,并避免未发送完的数据丢失。
具体过程由下图和文字一起解析:
- 第一次挥手:在挥手过程发生时,客户端向服务端发送一个
TCP 报文段
,这个特殊的报文段会设置首部的一个标志位(FIN比特
)设置为1,即FIN=1
,并会在序号字段中设置seq=u
。这时客户端会停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1
(终止等待1)状态,等待服务端的确认。 - 第二次挥手:服务端收到
FIN 报文段
之后,会发送ACK 报文段
,即确认报文段ACK=1
,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,即ack=u+1
,表明已经收到客户端的报文,同时会附带序号字段seq=v
。此时服务端进入CLOSE_WAIT
状态。此时的TCP处于半关闭状态
,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2
(终止等待2)状态,等待服务端发出的连接释放报文段。 - 第三次挥手:如果服务端也想断开连接,和客户端的第一次挥手一样,发给
FIN 报文段
(也称终止报文段)。服务端进入到LAST_ACK
的状态。FIN 报文段
设置FIN=1
,ACK=1
,seq=w
,确认号为ack=u+1
。服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。 - 第四次挥手:客户端收到
FIN 报文段
之后,会对其发送ACK 报文段
作为应答。ACK 报文段
设置为ACK=1
,把服务端的FIN 报文段
的序列号值 +1 作为自己ACK 报文段
的序列号值,即ack=w+1
,同时会附带序号字段seq=u+1
。此时客户端进入 TIME_WAIT 状态,这时的TCP并未释放掉,需要一段时间(一般设置2MSL)以确保服务端收到自己的ACK 报文段
之后才会进入CLOSED
状态。服务端收到ACK 报文
之后,就进入CLOSED
状态。
三、常见衍生问题
1、为什么需要三次握手而不是两次或者四次?
TCP的之所以采用三次握手,而不是两次握手,主要是因为三次握手能确保连接的可靠性和准确性
,可以阻止重复历史连接的初始化
。而不是四次握手,主要是考虑到效率问题,三次握手可以解决,就不再需要第四次。
- 三次握手能够防止已失效的请求报文段突然又传送到了服务端而造成连接的误判。在三次握手的过程中,如果客户端发出的连接请求因为网络原因没有被服务端接收到,客户端会再次发送连接请求。这时,即使服务端突然收到了旧的连接请求,由于不存在第三次握手,服务端不会错误地认为这是一次新的连接请求,从而避免了建立错误的连接。
- 三次握手有助于解决因网络拥塞导致的超时重传问题。在两次握手的情况下,如果因为网络拥塞导致超时重传建立连接的请求,可能会出现旧的请求成功得到响应,但由于客户端的校验不通过,导致连接被终止的情况。而三次握手通过序列号seq和确认号ack的交互,可以确保双方都进入数据可发送和接收的状态,从而避免这种情况的发生。
- 三次握手还能防止客户端发送SYN后,由于网络原因没有收到服务端的SYN+ACK回复,导致服务端出现垃圾连接的情况。在三次握手的过程中,服务端在接收到客户端的SYN请求并回复SYN+ACK后,会等待客户端的第三次握手确认,确保客户端也进入了已连接状态。如果客户端没有收到服务端的SYN+ACK回复,就不会发送第三次握手的确认,服务端也就不会进入已连接状态,从而避免了垃圾连接的出现。
- 至于为什么不需要四次握手,这主要是出于效率的考虑。四次握手相比三次握手多了一次交互过程,这会增加网络传输的延迟和开销,降低连接的建立速度。而且,从功能上来说,三次握手已经能够确保连接的可靠性和有效性,因此没有必要再进行第四次握手。
2、在三次握手中,SYN和ACK的作用是什么?
在TCP的三次握手中,SYN和ACK确保了连接的建立和通信的同步。
- SYN(Synchronize)是TCP协议中的一个标志位,用于在建立连接时进行通信的同步。在三次握手的第一次交互中,客户端发送一个
SYN=1,ACK=0
标志的数据包给服务端,请求建立连接。这个SYN包的作用是向服务端发起连接请求,并附带一个序列号(Sequence Number),用于标识后续发送的数据包。SYN标志位的设置表示客户端希望建立一个新的连接或确认一个连接请求。、 - ACK(Acknowledgement)是确认标志,用于确认接收到的数据包。在第二次握手中,服务端收到客户端的SYN包后,会发送一个
SYN=1,ACK=1
标志的数据包给客户端。这个SYN+ACK包的作用是告诉客户端,服务端已经收到了连接请求,并允许建立连接。同时,ACK=1
表示服务端对客户端发送的SYN包进行了确认。此外,服务端也会发送自己的序列号给客户端,用于后续的数据传输。 - 在第三次握手中,客户端收到服务端的SYN+ACK包后,会发送一个
SYN=0,ACK=1
的数据包给服务端。这个ACK包的作用是告诉服务端,客户端已经收到了SYN+ACK包,并对服务端的SYN包进行了确认。 - 至此,三次握手完成,TCP连接建立成功,双方可以开始进行数据传输。
在整个过程中,SYN和ACK标志位确保了连接的建立和通信的同步。SYN用于发起连接请求和标识序列号,而ACK用于确认接收到的数据包。这种机制可以有效地确保数据的可靠传输和连接的稳定性。
3、三次握手过程中可以携带数据吗?
在TCP的三次握手过程中,SYN和SYN+ACK报文段是不携带数据的,它们仅仅用于建立连接时的同步和确认。但是,最后一次的ACK报文段是可以携带数据的。这是因为当发送方收到对方的SYN+ACK报文段后,连接就已经建立了,此时发送方就可以立即发送数据,而这个数据就可以和ACK报文段一起发送,从而提高了效率。
虽然第三次握手可以携带数据,但在实际网络编程中,并不推荐这样做。因为这样做可能会带来一些问题,比如接收方可能无法及时准备好接收数据,导致数据丢失或乱序。
因此,通常建议将数据的发送放在三次握手完成之后进行,以确保数据的可靠传输。
4、如果第三次握手丢失了,客户端和服务端会如何处理?
如果TCP三次握手中的第三次握手(即客户端发送的ACK确认报文)丢失了,客户端和服务端会采取以下处理方式:
客户端:
- 客户端在发送完SYN报文并收到服务端的SYN+ACK报文后,会进入ESTABLISHED状态,认为连接已经建立。
- 客户端会期待接收服务端的数据或继续发送自己的数据,并发送ACK报文给服务端以确认之前接收到的SYN+ACK报文。
- 如果ACK报文在网络中丢失,客户端并不会立即知道,因为它已经认为连接建立成功。客户端会继续按照正常的TCP连接状态进行数据传输。
服务端:
- 服务端在发送SYN+ACK报文后,会进入SYN_RECV状态,等待客户端的ACK报文。
- 如果服务端在一定时间内没有收到客户端的ACK报文,它会认为ACK报文丢失了,并重新发送SYN+ACK报文给客户端,尝试重新建立连接。
- 服务端会重试多次发送SYN+ACK报文,每次等待的时间会逐渐增加,直到收到ACK报文或达到最大重试次数。
- 如果达到最大重试次数后仍然未收到ACK报文,服务端会关闭这个半开连接,并释放相关资源。
潜在问题:
- 由于客户端认为连接已经建立,它可能会继续发送数据。然而,由于服务端没有收到ACK报文并关闭了连接,这些数据可能会丢失。
- 如果客户端在发送完数据后尝试关闭连接,它可能会发送FIN报文给服务端。但由于服务端已经关闭了连接,这个FIN报文可能不会被正确处理,导致连接无法正常关闭。
解决方案:
- 为了避免上述问题,TCP协议设计了
超时重传机制
。当服务端重发SYN+ACK报文达到一定次数仍未收到ACK确认时,客户端也会因为长时间未收到服务端的数据而触发超时重传机制,重新发送ACK报文。这样,双方都有机会重新建立连接或处理丢失的数据包。 - 此外,应用层协议(如HTTP)通常也会有自己的超时和重试机制,以进一步确保数据的可靠传输。
当TCP三次握手中的第三次握手丢失时,客户端和服务端会通过各自的超时重传机制
来尝试重新建立连接或处理丢失的数据包。然而,在某些情况下,数据可能仍然会丢失或连接无法正常关闭,这需要应用层协议和更高级别的错误处理机制来进一步处理。
5、为什么需要四次挥手来关闭一个TCP连接?
四次挥手是TCP协议中用于关闭一个已建立的连接的过程,之所以需要四次挥手而不是更少或更多次,是为了确保连接的可靠关闭和数据完整性
。
- 四次挥手能够处理延迟的数据包。在网络通信中,由于数据包在传输过程中可能会遇到延迟,因此即使一方已经发送了关闭连接的请求,另一方可能仍然会接收到之前发送的数据包。通过四次挥手的过程,接收方可以确认所有待处理的数据包都已经收到并处理完毕,从而确保数据的完整性。
- 四次挥手能够解决
半关闭状态
的问题。半关闭状态是指在一方已经关闭连接,而另一方仍尝试发送数据的情况。通过四次挥手,即使一方已经发送了关闭连接的请求,另一方也可以继续发送数据,直到对方确认收到所有数据并发送关闭连接的请求。这样可以避免数据丢失和连接异常中断的情况。 - 通过四次交互,双方都能确保对方已经准备好关闭连接,并且所有数据都已经传输完毕,从而实现了连接的可靠关闭。
- 如果采用三次挥手,可能会导致数据丢失或连接状态不一致的问题。例如,如果客户端发送FIN包后直接关闭连接,而服务端还有未发送完的数据,那么这些数据将丢失。因此,四次挥手是确保TCP连接可靠关闭所必需的。
6、在四次挥手中,为什么客户端在发送FIN之后还要等待一段时间(2MSL)才进入CLOSED状态?
是为了确保连接的可靠关闭和避免一些潜在的网络问题。
- 等待2MSL可以确保客户端发送的最后一个ACK报文能够到达服务端。虽然服务端在接收到FIN报文后发送了ACK报文,但由于网络中的数据包可能会丢失或延迟,服务端可能没有收到客户端的ACK确认。因此,客户端等待一段时间,给服务端足够的时间来重新发送ACK报文,以确保服务端能够正确关闭连接。
- 等待2MSL可以避免已失效的连接请求报文段出现在本连接中。在等待期间,如果有之前发送的数据包由于某种原因延迟到达,客户端可以处理这些迟到的数据包,而不会将其误认为是新连接的数据包,从而保证了数据的完整性和准确性。
- 等待2MSL还可以确保客户端在发送完最后一个ACK报文后,有足够的时间让该报文在网络中消失,从而避免对新连接造成干扰。这是因为在网络拥塞或其他情况下,报文可能会在网络中存在一段时间,如果客户端立即进入CLOSED状态并开始新的连接,可能会与这些迟到的报文发生冲突。
客户端在发送FIN之后等待2MSL是为了确保连接的可靠关闭、避免数据丢失和混淆,以及防止对新连接造成干扰。这个等待时间是TCP协议为了保证连接关闭的可靠性和网络稳定性而设置的一个重要机制。
7、如果在四次挥手中,客户端发送的ACK丢失了,会发生什么?
如果在TCP四次挥手中,客户端发送的ACK丢失了,服务端将不会收到对FIN包的确认。TCP协议设计为具有可靠性,因此服务端会采取一些措施来处理这种情况。
- 具体来说,服务端在发送FIN包后,会等待客户端的ACK确认。如果服务端在一定时间内没有收到ACK,它会认为ACK丢失了,并重新发送FIN包。服务端会重试多次,每次等待的时间会逐渐增加,直到收到ACK或达到最大重试次数。如果达到最大重试次数后仍然未收到ACK,服务端可能会认为连接已经异常中断,并关闭连接或采取其他错误处理措施。
- 这种机制确保了即使在网络拥塞或丢包的情况下,TCP连接仍然能够可靠地关闭。客户端在发送ACK后,也会等待服务端的响应或超时。如果客户端在超时后仍未收到服务端的响应,它可能会重新发送ACK或采取其他恢复措施。
- 因此,尽管ACK丢失可能导致短暂的延迟和额外的网络流量,但TCP协议通过重传机制和超时重试确保了连接的可靠关闭。
8、TCP连接中的半连接队列和全连接队列是什么?
TCP连接中的半连接队列(也称为SYN队列)用于存储处于TCP三次握手过程中第一步的连接请求。
当服务端收到客户端发起的SYN请求后,内核会把该连接存储到半连接队列中,等待完成三次握手的过程。此时,连接请求还没有完成握手,因此被认为是“半连接”。如果半连接队列满了,新来的连接请求可能会被丢弃或者根据系统配置发送RST报文。
全连接队列就是已经完成三次握手,建立起连接的就会放在全连接队列中。
半连接队列的主要作用是管理并跟踪那些尚未完全建立的连接,确保在三次握手完成之前,这些连接请求能够得到妥善的处理。它是TCP协议保证连接可靠性和性能的重要机制之一。
需要注意的是,当服务端并发处理大量请求时,如果TCP半连接队列过小,就容易出现溢出的情况,导致后续的请求被丢弃,从而影响服务端的请求处理能力。因此,合理设置和调整半连接队列的大小对于优化网络性能和提升系统稳定性具有重要意义。
9、TCP连接中ISN(Initial Sequence Number)是什么?
在TCP连接中,ISN(Initial Sequence Number,初始序列号)是每个TCP连接在建立时由TCP协议为每一个数据包所赋予的序列号。它是TCP可靠传输的一个重要组成部分,用于确保数据的顺序性和完整性。
- 当TCP连接建立时,客户端和服务器都会选择一个初始序列号(ISN)作为它们发送的第一个数据包的序列号。这个序列号是一个随机值,通常不会重复,用于标识该连接中的每一个数据包的顺序。
- 在数据传输过程中,TCP协议会根据数据包的发送顺序为每个数据包分配一个递增的序列号。ISN可以看作是一个32比特的计数器,每4ms加1 。
- 通过序列号,接收方可以准确地按照发送方的发送顺序来重组数据,从而确保数据的顺序性。
- 此外,序列号还可以用于检测丢失或重复的数据包。当接收方发现数据包的序列号不连续时,它会向发送方发送一个ACK(确认)消息,请求发送方重传丢失的数据包。同样地,如果接收方接收到一个重复的数据包(即具有相同序列号的数据包),它可以通过序列号来识别并丢弃这个重复的数据包。
因此,ISN在TCP连接确保了数据的顺序性和完整性,为TCP的可靠传输提供了基础。
10、SYN攻击是什么?如何防范SYN攻击?
SYN攻击是一种利用TCP协议缺陷进行的黑客攻击手法,通过发送大量的半连接请求来耗费服务器的CPU和内存资源,使得服务器无法为正常用户服务。这种攻击方式破坏威力巨大,是所有黑客攻击事件中最常见又最容易被利用的一种。
防范SYN攻击的主要方法包括:
- 过滤网关防护: 这主要涉及到防火墙和路由器的设置。通过设置网关超时参数、使用SYN网关和SYN代理等方法,可以有效地过滤掉恶意的SYN请求,保护服务器免受攻击。
- 加固TCP/IP协议栈: 这包括采用一些安全机制和技术,如SynAttackProtect保护机制、SYN cookies技术、增加最大半连接数以及缩短超时时间等。这些措施能够增强TCP/IP协议栈的防御能力,对抗SYN攻击。
TCP/IP协议栈的调整可能会引起某些功能的受限,因此管理员应该在进行充分了解和测试的前提下进行此项工作。同时,防范SYN攻击需要综合考虑网络架构、安全策略和防护技术等多个方面,以构建多层次的安全防护体系。
11、为什么TCP连接建立需要发送序列号?
TCP连接建立需要发送序列号的原因主要有以下几点:
- 确保数据的顺序性: TCP是一个面向连接的、可靠的、基于字节流的传输层通信协议。在TCP通信中,发送方和接收方都需要按照数据的发送顺序来接收和处理数据。序列号用于标识每一个发送的数据包,确保接收方能够按照正确的顺序重组数据。
- 实现可靠传输: TCP通过序列号来实现数据的可靠传输。当接收方收到数据包后,会向发送方发送一个确认(ACK)消息,告知已经成功接收到的数据包的序列号。如果发送方在某个时间点内没有收到某个数据包的ACK,它会认为该数据包丢失,并重新发送该数据包。序列号使得发送方能够准确地知道哪些数据包已经成功发送并被接收,哪些数据包需要重传。
- 处理网络中的数据包乱序: 在网络传输过程中,由于网络拥塞、路由变化等原因,数据包可能会乱序到达接收方。通过序列号,接收方能够识别并重新排序这些乱序的数据包,确保数据的完整性和正确性。
- 流量控制和拥塞控制: TCP还利用序列号来实现流量控制和拥塞控制。发送方会根据接收方的确认消息和当前的网络状况来调整发送速率,以避免网络拥塞和数据丢失。序列号在这个过程中起到了关键作用,帮助发送方和接收方协调数据的发送和接收。
TCP连接建立需要发送序列号是为了确保数据的顺序性、实现可靠传输、处理网络中的数据包乱序以及实现流量控制和拥塞控制。这些功能共同保证了TCP能够提供高效、可靠的数据传输服务。
12、在TCP通信中,如果一方突然崩溃,另一方如何知道?
在TCP通信中,如果一方突然崩溃(例如,由于硬件故障、操作系统崩溃或应用程序异常终止),另一方通常通过以下几种机制来检测这种情况:
- 心跳机制(Keep-Alive): TCP本身并没有一个显式的“心跳”机制,但许多操作系统和应用程序层协议实现了这种机制。通过定期发送小的数据包(通常称为“探测包”或“心跳包”),接收方可以通知发送方它仍然存活并且连接仍然有效。如果发送方在一段时间内没有收到响应,它可能会认为接收方已经崩溃,并关闭连接。
- 超时重传和重试: TCP使用超时重传机制来处理丢失的数据包。当发送方发送一个数据包后,它会等待一个确认(ACK)。如果在一定的超时时间内没有收到ACK,发送方会重传该数据包。如果经过多次重传仍然未收到确认,发送方会认为连接已经中断,并关闭连接。同样,接收方在收到乱序的数据包或数据包丢失时,也会通过发送重复ACK或通知发送方进行快速重传来处理。
- 应用层协议: 除了TCP本身的机制外,应用层协议(如HTTP、FTP等)通常也会实现自己的连接管理和错误处理机制。这些协议可能会定义特定的消息或命令来通知对方连接已经中断,或者通过超时和重试策略来处理突然的崩溃。
- 操作系统和网络栈的通知: 在某些情况下,当一方崩溃时,操作系统或网络栈可能会向另一方发送一个特殊的信号或错误消息。例如,当TCP连接的一方异常终止时,操作系统可能会向另一方发送一个RST(重置)数据包来关闭连接。
由于网络的复杂性和不确定性,有时候即使一方崩溃,另一方也可能无法立即检测到。这取决于网络状况、操作系统的实现以及应用层协议的设计。因此,在设计和实现基于TCP的应用程序时,应该考虑到这种可能性,并采取相应的错误处理和恢复策略。