网络面试-0x11 TCP为什么需要三次握手和四次挥手?
一、三次握手
三次握手
[three-way-handshake]:客户端和服务器总共发送3个包,以建立TCP连接。
什么是连接了?主要作用是什么?
连接:
主要作用:为了确认双方的接收能力
和发送能力
是否正常,指定自己的初始化序列号为后面的可靠性传送做准备。
过程如下:
1)
第一次握手
:客户端发送搞一个SYN报文给服务端,并且报文中指明了客户端的初始化系列seq=ISN(c),此时,客户端处于SYN_SENT状态 2)
第二次握手
:服务器收到客户端的SYN包,处理之后,发送自己的SYN+ACK包,将客户端的ISN+1作为ack的值,此时,服务器处于SYN_RCVD的状态。 3)
第三次握手
:客户端发送一个ACK报文,seq=ISN+1。此时客户端处于ESTABLISHED状态。 服务器收到ACK报文之后,也处于ESTABLISHED状态,此时,双方已建立起了连接。 每次握手的作用:
第一次握手
:客户端的发送能力、服务器的接收能力是正常的。
第二次握手
:服务器的接收、发送能力正常,客户端的接收、发送能力是正常的。 不过,此时服务器并不能确认客户端的接收能力是否正常。
第三次握手
:客户端接收、发送能力正常,服务器自己的发送、接收能力也正常。
1、为什么不是两次握手?
如果两次握手,发送端能够确定自己发送的信息对方能够收到,而对方发送的消息,发送端也能够收到。 接收端只能够确定对方发送的消息自己能够收到,而无法确定自己发送的消息对方能够收到。
2、第2次握手传回了ACK,为什么要穿SYN?
ACK 是告诉客户端发来的数据已经接受无误,而传回SYN是为了把自己的初始化序列号seq同步给客户端。
二、 四次挥手
TCP 终止一个连接, 需要经过四次发包的过程。
挥手过程:
1)
第一次挥手
:客户端发送一个FIN报文,报文中指定一个序列号。 此时,客户端处于FIN_WAIT1状态, 停止发送数据,等待服务端的确认。seq=x 2)
第二次挥手
:服务端接收到FIN报文之后,发送ACK报文, ack=x+1, seq=Y, 此时,服务端处于CLOSE_WAIT状态。
3)
第三次挥手
:如果服务端也想断开连接, 和客户端的第一次挥手是一样的,发送FIN报文, 指定一个序列号, 此时,服务器处于LAST_ACK的状态。4)
第四次挥手
:客户端收到FIN之后,一样发送一个ACK报文作为应答,且把服务器的序列号值+1作为自己ACK报文的序号值,此时客户端处于TIME_WAIT状态。需要过一阵子以确保服务端收到自己的ACK报文之后才会进入CLOSED状态,服务端收到ACK报文之后,就处于关闭比连接了,处于CLOSED状态。 1、 四次挥手原因
服务端在收到客户端断开连接FIN报文后,并不会立即关闭连接, 而是先发送一个ACK包线告诉客户端收到关闭连接的请求,只有当服务器的所有报文发送完毕之后,才发送FIN报文断开连接,因此需要四次挥手。
2、CLOSE-WAIT 和 TIME-WAIT 的状态和意义
CLOSE-WAIT
: 服务器收到客户端关闭连接的请求并告诉客户端自己已经成功收到了请求之后, 服务器进入CLOSE-WAIT状态,然而此时有可能服务端还有一些数据没有传输完成,因此不能立即关闭连接, 而CLOSE-WAIT状态就是为了保证服务器在关闭连接之前将待发送的数据发送完成。
TIME-WAIT
:发生在第四次挥手,当客户端收到那个服务端发送ACK确认报文后进入该状态,若取消该状态,即客户端在收到服务端的FIN报文后立即关闭连接,此时,
(1)服务端相应的端口并没有关闭,若客户端在相同的端口立即建立了新的连接,则有可能接收到上次连接残留的数据包,可能会导致不可以预料的异常出现。—— 保证没有收到残余的数据
(2)除此之外,假设客户端最后一次发送的ACK包在传输时候丢失,由于TCP协议的超时重传机制,服务端将重发FIN报文,若客户端并没有维持TIME-WAIT状态而直接关闭的话,当收到服务端重新发送的FIN包时,客户端就会用RST包来响应服务端,这就会使得对方认为是有错误发生,然而其实只是正常的关闭连接过程,并没有出现异常情况。 —— 保证最后一个ACK到达
3、TIME-WAIT 状态会导致什么问题?怎么解决?
场景
: 高并发业务
在高并发短连接的TCP服务器上,当服务器处理完请求后,主动请求关闭连接,这样服务器上会有大量的连接处于TIME_WAIT状态,服务器维护每个连接需要一个socket,也就是每个连接会占用一个文件描述符,而文件描述符的使用有上限的,如果持续高并发,会导致一些正常的连接失败。
解决方案
:修改配置或设置SO_REUSEADDR套接字,使得服务器处于TIME-WAIT状态下的端口能够快速回收和重用。
4、TIME-WAIT为什么是2MSL?
当客户端发出最后的ACK确认报文时,并不能够确定服务器端能够接收到该段报文。 所以,此时会设置一个2MSL
的计时器。2MSL即是服务器端发出FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
若是服务器没有收到ACK报文,再次向客户端发送FIN报文。 如果客户端在2MSL内收到了服务器再次发来的FIN报文,说明服务器由于一些原因并没有收到客户端发出的ACK确认报文。客户端将再次向服务器发出ACK确认报文,并重新开始2MSL计时。
所以:客户端要经历2MSL市场的TIME-WAIT阶段,为的是确认服务器能否接收到客户端发出的ACK确认报文。
区分 MSL, TTL, RTT
1、MSL(Maximum Segment Lifetime) 报文最大生存空间,任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃,因为TCP报文(segment)是IP数据报(datagram)的数据部分。
每个具体的TCP实现都必须选择一个确定的MSL值。RFC 1122建议是2分钟。
2、TTL(time to live)生存时间。ip头中有一个TTL域,这个生存时间是由源主机设置初始值但并不是存的具体时间,而是存储的一个IP数据报可以经过的最大路由数,每经过一个处理他的路由器此值就-1,当此值位0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。
2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。
TTL与MSL是有关系的但不是简单的相等关系,MSL要大于等于TTL。
3、RTT(round-trip time)客户端到服务器往返所花的时间
。TCP含有动态估算RTT的算法。TCP还持续估算一个给定连接的RTT,这是因为RTT受网络传输拥塞程序的变化而变化。
表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。
一般认为单向时延=传输时延t1+传播时延t2+排队时延t3
t1是数据从进入节点到传输媒体所需要的时间,通常等于数据块长度/信道带宽
t2是信号在信道中需要传播一定距离而花费的时间,等于信道长度/传播速率(光纤中电磁波的传播速率约为210^5 km/s,铜缆中2.310^5 km/s)
t3可笼统归纳为随机噪声,由途径的每一跳设备及收发两端负荷情况及吞吐排队情况决定(包含互联网设备和传输设备时延)
5、有很多TIME-WAIT状态如何解决?
服务器可以设置SO_REUSEADDR
套接字选项来通知内核,如果端口被占用,但 TCP 连接位于 TIME_WAIT 状态时可以重用端口。如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时 SO_REUSEADDR 选项就可以避免 TIME-WAIT 状态。
也可以采用长连接的方式减少 TCP 的连接与断开,在长连接的业务中往往不需要考虑 TIME-WAIT 状态,但其实在长连接的业务中并发量一般不会太高。
6、有很多CLOSE-WAIT状态如何解决?
1)检查是不是自己的代码问题(看是否服务端程序忘记关闭连接),如果是,则修改代码
2)调整系统参数,包括句柄相关的参数和TCP/IP的参数,一般一个CLOSE_WAIT会维持至少2个小时的时间,我们可以通过调整参数来缩短这个时间。
常见的关键缩写:
CWR: 拥塞窗口减(发送方降低它的发送速率)
ECE: ECN会显(发送方接收到一个更早的拥塞通告)
URG: 紧急(紧急指针字段有效 —— 很少被使用)
ACK: 确认(确认号字段有效 —— 连接建立以后,一般都启用状态)
PSH:推送(接收方应尽快给应用程序传送这个数据 —— 没被可靠地实现或用到)
RST:重置连接(连接取消,经常是因为错误)
SYN:用于初始化一个连接的同步序号
FIN:该报文端发送方已经结束向对方发送数据。
三、 总结
公众号:
技术小难
简书
博客园 链接需要替换
CSDN
知乎
掘金
segmentfault
本文由mdnice多平台发布