【计算机网络】三次握手和四次挥手
目录
7、ISN(Initial Sequence Number)是固定的吗?
4、TIME_WAIT 和 CLOSE_WAIT 有什么区别?
6、 为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?
注:部分内容转自猿人谷,原文链接:https://blog.csdn.net/hyg0811/article/details/102366854
三次握手(TCP连接建立)
三次握手(Three-way Handshake)是TCP协议在建立连接时的过程,确保客户端和服务器双方都能正常发送和接收数据。简单来说就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。
开始进行三次握手:
- 第一次握手:SYN(同步序列编号)
客户端发送一个SYN报文(SYN=1)到服务器,并选择一个初始序列号(seq=x)。此时客户端进入SYN_SENT状态。
首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
- 第二次握手:SYN-ACK(同步确认)
服务器收客户端到SYN报文后,会回复一个SYN-ACK报文(SYN=1,ACK=1),确认客户端的序列号(ack=x+1),并选择自己的初始序列号(seq=j)。此时服务器进入SYN_RCVD状态。
在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
- 第三次握手:ACK(确认)
客户端收到SYN-ACK报文后,发送一个ACK报文(ACK=1,ack=y+1,seq=x+1)。当然,也是一样把服务器的SYN作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时连接建立,客户端和服务器进入ESTABLISHED状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
在socket编程中,客户端执行connect()时,将触发三次握手。

// 伪代码表示
Client -> Server: SYN=1, seq=x
Server -> Client: SYN=1, ACK=1, seq=y, ack=x+1
Client -> Server: ACK=1, ack=y+1, seq=x+1
1、三次握手的作用
- 使得通讯双发都做好通讯的准备
- 告诉对端本端通讯所选用的报文标识号
- 防止已失效的连接请求报文段又突然传递到了服务端,从而产生错误
2、为什么需要三次握手,两次不行吗?
- 第一次握手:客户端客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
- 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
- 第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
如果出现两次握手则会出现以下情况。“已失效的连接请求报文段”的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接”。主要目的防止 server 端一直等待,浪费资源。
3、三次握手那个阶段会出现异常?
4、三次握手那个阶段容易出现攻击?
5、SYN攻击是什么?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstat 命令来检测 SYN 攻击。
netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
6、什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
关于SYN-ACK 重传次数的问题:服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
7、ISN(Initial Sequence Number)是固定的吗?
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。seq随时间而变化,因此每个连接都将具有不同的seq。seq可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 seq(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 seq 是固定的,攻击者很容易猜出后续的确认号,因此 seq 是动态生成的。
8、 三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据。
假如第一次握手可以携带数据,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
四次挥手(TCP连接释放)
四次挥手是TCP协议在断开连接时的过程,确保数据能够完全传输并安全关闭连接。
首先建立一个连接需要三次握手,而终止一个连接要经过四次挥手。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。
刚开始双方都处于ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下:
- 第一次挥手:FIN(终止连接)
主动关闭方(如客户端)发送FIN报文(FIN=1,seq=u),报文中会指定一个序列号,此时客户端进入FIN_WAIT_1状态。
即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
- 第二次挥手:ACK(确认)
被动关闭方(如服务器)收到FIN报文后,发送ACK报文(ACK=1,ack=u+1,seq=v),且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端进入CLOSE_WAIT状态。此时主动方进入FIN_WAIT_2状态。
即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。
- 第三次挥手:FIN(终止连接)
被动关闭方完成数据发送后,如果服务端也想断开连接了,和客户端的第一次挥手一样,发送自己的FIN报文,且指定一个序列号(FIN=1,ACK=1,ack=u+1,seq=w),此时服务端进入LAST_ACK状态。
即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。
- 第四次挥手:ACK(确认)
主动关闭方(客户端)收到FIN报文后,发送ACK报文(ACK=1,ack=w+1,seq=u+1)作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端进入TIME_WAIT状态。等待2MSL(最大报文生存时间)以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
在socket编程中,任何一方执行close()操作即可产生挥手操作。

// 伪代码表示
Client -> Server: FIN=1, seq=u
Server -> Client: ACK=1, ack=u+1, seq=v
Server -> Client: FIN=1, ACK=1, ack=u+1, seq=w
Client -> Server: ACK=1, ack=w+1, seq=u+1
1、 挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
2、挥手可不可三次?
3、TIME_WAIT 状态存在的意义?
TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。
TIME_WAIT 状态是:主动断开连接的一端收到对端的 FIN 报文段并且将 ACK 报文段发出后的一种状态。意义:1) 保证迟来的报文段能被识别并丢弃。2) 保证可靠的终止 TCP 连接。保证对端能收到最后的一个 ACK,如果 ACK 丢失,在TIME_WAIT状态本端还可以接受到对端重传的FIN报文段并重新发送ACK所以 TIME_WAIT 的存在时间为 2MSL。
4、TIME_WAIT 和 CLOSE_WAIT 有什么区别?
CLOSE_WAIT 是被动关闭的一端在接收到对端关闭请求(FIN 报文段)并且将 ACK 发送出去后所处的状态,这种状态表示:收到了对端关闭的请求,但是本端还没有完成 工作,还未关闭。
TIME_WAIT 状态是主动关闭的一端在本端已经关闭的前期下,收到对端的关闭请 求(FIN 报文段)并且将 ACK 发送出去后所处的状态,这种状态表示:双方都已经完成 工作,只是为了确保迟来的数据报能被是被并丢弃,可靠的终止 TCP 连接。
5、 四次挥手释放连接时,等待2MSL的意义?
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
两个理由:
- 保证客户端发送的最后一个ACK报文段能够到达服务端。
这个ACK报文段有可能丢失,使得处于LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认,服务端超时重传FIN+ACK报文段,而客户端能在2MSL时间内收到这个重传的FIN+ACK报文段,接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务端都进入到CLOSED状态,若客户端在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到服务端重传的FIN+ACK报文段,所以不会再发送一次确认报文段,则服务端无法正常进入到CLOSED状态。
- 防止“已失效的连接请求报文段”出现在本连接中。
客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。
6、 为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?
理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
7、如何查看 tcp 连接的状态?
- Netstat :执行结果中 State 列表示的就是 tcp 连接状态
- ss: 执行结果中第一列为 tcp 连接状态
8、画出 tcp 报头信息?

更多推荐


所有评论(0)