北京上海广州深圳武汉
作者:互联网
三交四浪是各公司常见的考点,也有一定程度的歧视。它们也被一些面试官用作热身问题。很多朋友说这个问题一开始回答的很好,但是越回答越出冷汗,最后就不吃了。
我见过这样一个典型的面试场景:
面试官:请介绍一下三次握手
求职者:第一次握手是客户端向服务器发送消息。第二次握手是服务器收到消息后会回复客户端一条消息。第一个三次握手是客户端收到消息后向服务器发送消息。三次握手成功。
面试官:然后呢?
求职者:这是三次握手中的过程。很简单。
面试官:。。。。。。
(外星人:给你的一首很酷的歌)
记得四面谷的一句话:面试的问题越简单,坑一般隐藏的越大,一般需要扩大问题。申请人以上回答是否有误?当然可以,但是可能和面试官的预期有些距离。
希望大家用以下问题阅读,收获更多。
请画一个三交四浪的示意图
为什么连接的时候是三次握手?
什么是半连接队列?
初始序列号是固定的吗?
三次握手过程中可以携带数据吗?
如果三次握手失败,客户端服务器会怎么做?
什么是SYN攻击?
为什么需要波四次?
挥手四次释放连接等待2MSL是什么意思?
1.三次握手
三向三向握手实际上是指当建立一个TCP连接时,客户机和服务器总共需要发送三个数据包。三次握手的主要作用是确认双方的接收能力和发送能力是否正常,并指定自己的初始化序列号,为后续的可靠传输做准备。本质上是连接到服务器的指定端口,建立TCP连接,同步双方的序列号和确认号,交换TCP窗口大小信息。
首先,客户端处于关闭状态,服务器处于监听状态。
进行三次握手:
第一次握手:客户端向服务器发送SYN消息,并指示客户端的初始化序列号is。此时,客户端处于SYN_SEND状态。
报头同步位SYN=1,初始序列号seq=x,SYN=1不能携带数据,但消耗一个序列号。
第二次握手:服务器收到客户端的同步消息后,会用自己的同步消息进行回复,并指定自己的初始化序列号。同时,将客户端的ISN+1作为ACK的值,表示已经收到客户端的SYN。此时,服务器处于SYN_REVD状态。
在确认消息段中,SYN=1,ACK=1,确认号ack=x+1,初始序列号seq=y..
三次握手:客户端收到SYN消息后,会发送ACK消息。当然也是以服务器的ISN+1作为ACK值,表示已经收到服务器的SYN消息,此时客户端处于建立状态。收到确认消息后,服务器也处于“已建立”状态。此时,双方已经建立了联系。
ACQUIRY ACK = 1,ACQUIRY number ACK = y+1,序列号seq=x+1 (seq=x开头,所以第二段应该是+1)。ack段可以携带数据,但是如果它不携带数据,则不消耗序列号。
发送第一个SYN的一端将执行主动打开,接收该SYN并将其发送回下一个SYN的另一端将执行被动打开。
在套接字编程中,当客户端执行connect()时,将触发三次握手。
1.1为什么需要三次握手?不能做两次吗?
要理解这个问题,首先需要理解三次握手的目的是什么,是否只用两次握手就能达到同样的目的。
第一次握手:客户端发送网络数据包,服务器接收。
这样服务器就可以得出客户端的发送能力和服务器的接收能力正常的结论。
第二次握手:服务器发出契约,客户端接收。
这样客户端就可以得出服务器和客户端收发能力正常的结论。但是此时服务器无法确认客户端的接收能力是否正常。
三次握手:客户端发布合同,服务器接收合同。
这样服务器就可以得出结论,客户端的收发能力正常,服务器本身的收发能力也正常。
所以需要三次握手来确认双方的收发能力是否正常。
想象一下如果你用两次握手,会出现以下情况:
如果客户端发送连接请求,但是连接请求消息丢失并且没有收到确认,则客户端会再次重新发送连接请求。收到确认后,连接就建立了。数据传输完成后,释放连接,客户端发出两个连接请求报文段,第一个丢失,第二个到达服务器,但是第一个丢失的报文段只在一些网络节点停留较长时间,在连接释放后的某个时间到达服务器。此时,服务器误认为客户端发送了新的连接请求,于是向客户端发送确认消息段,同意建立连接。没有三次握手,只要服务器发一个确认,就建立了新的连接。此时客户端忽略了服务器发送的确认,不发送数据,所以服务器等待客户端发送数据,浪费资源。
1.2什么是半连接队列?
服务器第一次从客户端接收到SYN后,将处于SYN_RCVD状态。此时,双方都没有完全建立连接,服务器会将请求的连接放在这种状态的队列中。我们称这个队列为半连接队列。
当然,还有一个全连接队列,也就是说,如果三次握手已经完成,连接就会被放在全连接队列中。如果队列已满,可能会发生数据包丢失。
在这里,我想补充一点关于同步确认重传的数量:
服务器发送SYN-ACK包后,如果没有收到客户端确认包,服务器第一次重传,等待一段时间没有收到客户端确认包,然后第二次重传。如果重传次数超过系统指定的最大重传次数,系统将从半连接队列中删除连接信息。
注意每次重传的等待时间不一定相同,一般都是指数增长的,比如间隔时间为1s,2s,4s,8s…
1.3 ISN(初始序列号)是固定的?
当一端发送其SYN以建立连接时,它为连接选择一个初始序列号。ISN随着时间的推移而变化,因此每个连接都将有一个不同的ISN。Is可视为32位计数器,每4ms递增1。这样选择序号的目的是为了防止网络中延迟的数据包以后再次传输,导致对某个连接的错误解读。
三次握手的一个重要作用就是在客户端和服务器端之间交换ISN(初始序列号),这样对方接下来接收数据的时候就可以知道如何根据序列号组装数据了。如果is是固定的,攻击者很容易猜到后续的确认号,所以is是动态生成的。
1.4三次握手可以携带数据吗?
事实上,当我在三次握手时,我可以携带数据。然而,第一次和第二次握手不能携带数据
为什么会这样?可以想到一个问题。如果第一次握手可以携带数据,那么如果有人想恶意攻击服务器,那么他每次都会在第一次握手中把大量数据放入SYN消息中。因为攻击者简单的忽略了服务器的收发能力是否正常,然后疯狂的专注于重复出现的SYN消息,会让服务器花费大量的时间和内存空间来接收这些消息。
也就是说第一次握手不能释放数据,其中一个很简单的原因就是会让服务器更容易受到攻击。第三次,客户端已经处于“已建立”状态。就客户端而言,他已经建立了连接,已经知道服务器的收发能力正常,所以能够携带数据没有错。
1.5什么是syn攻击?
服务器的资源是在第二次握手时分配的,而客户端的资源是在三次握手完成时分配的,因此服务器容易受到SYN泛洪攻击。SYN攻击是指客户端在短时间内伪造大量不存在的IP地址,不断向服务器发送SYN数据包,而服务器回复确认数据包,等待客户端确认。因为源地址不存在,服务器需要不断重新发送,直到超时。这些伪造的SYN数据包会长时间占用未连接的队列,导致正常的SYN请求因为队列已满而被丢弃,从而造成网络拥塞甚至系统瘫痪。SYN攻击是典型的DoS/DDoS攻击。
检测SYN攻击非常方便。当你在服务器上看到大量的半连接状态,尤其是源IP地址是随机的时候,基本上可以断定是SYN攻击。在Linux/Unix上,可以使用系统自带的netstats命令检测SYN攻击。
netstat -n -p TCP | grep SYN_RECV
抵御SYN攻击的常见方法如下:
缩短同步超时时间
增加最大连接数
过滤网关保护
SYN cookies技术
2.挥手四次
建立一个连接需要三次握手,但是终止一个连接需要四波(也有人叫四次握手)。这是TCP的半闭造成的。所谓半关机,就是TCP在一个连接的一端完成发送后,提供从另一端接收数据的能力。
TCP连接的移除需要发送四个数据包,所以称为四次握手,客户端或服务器都可以主动发起挥舞动作。
首先,如果客户端首先发起关闭请求,双方都处于“已建立”状态。四波的过程如下:
第一次Wave:客户端发送一条FIN消息,消息中会指定一个序列号。此时,客户端处于FIN_WAIT1状态。
即发送一个连接释放消息段(FIN=1,序号seq=u),再次停止发送数据,主动关闭TCP连接,进入FIN_WAIT1状态,等待服务器确认。
第二次挥手:服务器收到FIN后会发送一条ACK消息,以客户端的序列号值+1作为ACK消息的序列号值,表示已经收到客户端的消息,此时服务器处于CLOSE_WAIT状态。
即服务器收到连接释放报文段后,发出确认报文段(ACK=1,确认号ack=u+1,序列号seq=v),服务器进入CLOSE_WAIT状态,此时TCP处于半关闭状态,客户端到服务器的连接被释放。客户端收到服务器的确认后,进入FIN_WAIT2状态,等待服务器发送的连接释放消息。
第三波:如果服务器也想断开,就像客户端的第一波一样,发一条FIN消息,指定一个序列号。此时,服务器处于LAST_ACK状态。
即如果服务器没有数据要发送给客户端,则服务器发送连接释放消息段(FIN=1,ACK=1,seq=w,ack=u+1),服务器进入LAST_ACK状态,等待客户端的确认。
第四波:客户端收到FIN后,发送ACK消息作为回复,将服务器的序列号值+1作为自身ACK消息的序列号值。此时,客户端处于时间等待状态。需要一段时间才能保证服务器收到自己的ACK消息后进入CLOSED状态,服务器收到ACK消息后处于CLOSED状态。
即从服务器接收到连接释放消息段后,客户端发送确认消息段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT状态。此时不释放TCP,需要等待定时器设置的2MSL时间,客户端才进入CLOSED状态。
收到一个FIN只意味着这个方向没有数据流。客户端执行主动关机并进入TIME_WAIT是正常的,而服务器通常执行被动关机并不进入TIME_WAIT状态。
在socket编程中,任何一方都可以执行close()操作生成wave操作。
2.1为什么需要波四次?
因为服务器收到客户端的SYN连接请求消息时,可以直接发送SYN+ACK消息。确认消息用于响应,同步消息用于同步。但是,当连接关闭时,服务器收到FIN消息时,很可能不会立即关闭SOCKET,所以只能回复一条ACK消息,告诉客户端“我收到了你发送的FIN消息”。在我的服务器上的所有消息都发送完之前,我不能发送FIN消息,所以我不能一起发送它们。所以你需要波四次。
2.2 2MSL等待状态
而TIME_WAIT状态也变成了2MSL等待状态。每个特定的传输控制协议实现必须选择一个最大的网段生存期(MSL),这是网络中丢弃任何网段之前的最长时间。这个时间是有限的,因为TCP段在网络中是作为IP数据报传输的,而IP数据报具有限制其生存期的TTL字段。
对于特定实现给出的MSL值,处理原则是,当TCP执行主动关闭并发回最后一个确认时,连接必须在时间等待状态下保持两次MSL。这允许传输控制协议再次发送最后一个确认,以防该确认丢失(另一端超时并重新发送最后一个FIN)。
此2MSL等待的另一个结果是,定义此连接的套接字(客户端的IP地址和端口号,服务器的IP地址和端口号)在此TCP连接的2MSL等待期间无法再使用。该连接只有在2MSL完成后才能再次使用。
2.3四次挥手释放连接等待2MSL是什么意思?
MSL是最大分段寿命的英文缩写,可以翻译成“最大分段寿命”。这是网络上任何消息存在的最长时间,超过此时间后,该消息将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为该确认可能丢失,所以处于最后确认状态的服务器将不会接收到确认确认消息。服务器将在超时后重新发送该FIN-ACK,然后客户端将再次重新发送确认,并重新启动时间等待计时器。最后,客户端和服务器都可以正常关闭。假设客户端没有等待2MSL,而是在发送ACK后直接释放关机。一旦确认丢失,服务器就不能正常进入关闭连接状态。
两个原因:
确保客户端发送的最后一个确认消息段可以到达服务器。
ACK报文段可能丢失,使得处于LAST-ACK状态的b无法接收到发送的FIN+ACK报文段的确认,服务器随时间重传FIN+ACK报文段,而客户端可以在2MSL内接收到重传的FIN+ACK报文段,然后客户端重传一次确认,重启2MSL定时器,最终客户端和服务器均进入CLOSED状态。如果客户端在TIME-WAIT状态下没有等待一段时间,而是在发送了ACK报文段后立即释放连接,则不会收到服务器重发的FIN+ACK报文段,因此不会再次发送确认报文段,服务器也不会正常进入CLOSED状态。
防止“过期的连接请求消息段”出现在此连接中。
在发送最后一个确认消息段后,客户端可以使该连接期间生成的所有消息段从网络中消失,以便该旧的连接请求消息段不会出现在下一个新的连接中。
2.4为什么TIME_WAIT状态需要2MSL才能返回CLOSE状态?
理论上,当四条消息都发出后,可以直接进入CLOSE状态,但网络可能不可靠,最后一条ACK可能会丢失。因此,时间等待状态用于重发可能丢失的确认消息。
3.摘要
《TCP/IP详解第一卷:协议》有一个TCP状态转移图,很有代表性,有助于大家了解三次握手和四波的状态变化。如下图所示,粗实线箭头表示正常客户端状态转换,粗虚线箭头表示正常服务器状态转换。
之后面试官会问你三次握手,四次挥手。就把这篇文章扔给他。他的问题都在这里。
标签:广州,深圳,ACK,握手,SYN,服务器,武汉,连接,客户端 来源: https://www.cnblogs.com/daybydaye/p/14153004.html