三次握手
各种参数的意义
SYN:标志位,同步序列编号(Synchronize Sequence Numbers)栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。
seq:seq的初始值在不同系统实现不一样,一般为随时间增长的值。当seq超过4字节存储空间后从0开始。在某个方向上传输N个字节的数据,序列号就+N,因此seq用于确认在某个方向上传输的字节数。如果传输的数据字节为0,即只有首部,那序列号还增加吗?当syn 或 fin被置1,虽然报文里长度为0,计算ACK时我们可以认为其长度为1。其他情况(如只有ack)不增加。seq的初始值由算法随机生成。客户端和服务端都会随机生成一个seq。两者在数据传递的时候交替作为ack和seq。接收放将ack减去初始的seq就可以得到报文的长度(猜的)
ACK:大写的ACK代表TCP Flags 控制位中的 确认序号标志,ACK=1的时候表示确认序号标志有效,ACK=0表示报文中不含确认信息可以忽略。
ack:小写的ack意思是 你第一次握手从client发送SYN包到server得时候携带的seq=0,当server接收到client发送的SYN包时会携带SYN,ACK包,seq=0,ack= 1(client中的seq+1), 表示消耗了(client第一次握手的seq)。ack就是确认序列号
四个状态
LISTEN:监听状态,服务端准备好等待连接的状态。
SYN-SEND:同步已发送状态,客户端发起第一次请求之后,没有接收到服务端的应答属于这个状态
SYN-RCVD:同步已收到状态,服务端接收到客户端请求之后进入到这个状态,且立即发出应答请求。
ESTABLISHED:建立连接状态,客户端在接受到服务端的应答,并向服务端发起第二次的握手之后进入这个状态。服务端在接收到客户端的应答之后也进入这个状态
面试的问题
1.为什么是三次握手,两次握手不行嘛?
不行,防止国企的连接请求突然头传递到服务器,从而产生错误;确认两者发送和接受的能力都正常;双方确认对方的初始序列号值。
- 防止已过期的连接请求报文突然又传送到服务器,因而产生错误
在双方两次握手即可建立连接的情况下,假设客户端发送 A 报文段请求建立连接,由于网络原因造成 A 暂时无法到达服务器,服务器接收不到请求报文段就不会返回确认报文段,客户端在长时间得不到应答的情况下重新发送请求报文段 B,这次 B 顺利到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,客户端在收到 确认报文后也进入 ESTABLISHED 状态,双方建立连接并传输数据,之后正常断开连接。此时姗姗来迟的 A 报文段才到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,但是已经进入 CLOSED 状态的客户端无法再接受确认报文段,更无法进入 ESTABLISHED 状态,这将导致服务器长时间单方面等待,造成资源浪费。
- 三次握手才能让双方均确认自己和对方的发送和接收能力都正常
第一次握手:客户端只是发送处请求报文段,什么都无法确认,而服务器可以确认自己的接收能力和对方的发送能力正常;
第二次握手:客户端可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
第三次握手:服务器可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
可见三次握手才能让双方都确认自己和对方的发送和接收能力全部正常,这样就可以愉快地进行通信了。
- 告知对方自己的初始序号值,并确认收到对方的初始序号值
TCP 实现了可靠的传输,原因之一就是 TCP 报文段中维护了序号字段和确认序号字段,也就是图中的 seq 和 ack,通过这两个字段双方都可以知道在自己发出的数据中,哪些是已经被对方确认接收的。这两个字段的值会在初始序号值得基础递增,如果是两次握手,只有发起方的初始序号可以得到确认,而另一方的初始序号则得不到确认。
2.那么四次可以嘛?
- 多余了,该确认的都确认了
3.为什么连接的时候SYN需要消耗一个序列号
- 因为 SYN 包需要确认,如果不占用序号的话,就无法辨别 ACK 包确认的是哪一个报文。
4.双方同时发起连接请求,最终会有几个连接
- 一个
5.在建立tcp连接的时候,一个旧的SYN请求到服务端时候会怎样?
比较复杂,看情况,会被重置然后继续链接
6.第三次握手失败会怎样?
- 当计时器超时了而 B 还没收到 A 的应答报文,B 就认为它之前发送的 SYN+ACK 报文已丢失,会触发超时重传,重传次数默认 5 次;
- 如果重传指定次数后还没收到应答,则 B 就会关闭连接;
-
此时 B 可能处于 SYN-RECEIVED 状态或者 CLOSED 状态:
- CLOSED 状态:B 发送重置报文给 A,A 收到后就关闭连接;
- SYN-RECEIVED 状态:如果 B 之后收到正常的应答报文(第 4 行),那么连接成功建立;如果收到传输数据的请求(第 5 行),那么连接也能成功建立,因为传输数据的报文包含了应答号
四次挥手
状态
FIN-WAIT-1:主动发起关闭的一方,在发送第一次关闭连接的请求之后进入到这个状态
FIN-WAIT-2:主动发起关闭的一方,在接收到被关闭方的第一次关闭应答请求之后,进入到这个状态。
TIME-WAIT:主动发起关闭的一方,在接收到被关闭方的第二次关闭应答请求之后进入到这个状态。
CLOSED-WAIT:被关闭方在接收到主动关闭方的第一次关闭连接请求之后进入到这个状态,这个状态的被关闭方还能继续发送信息。
LAST-ACK:被关闭方在发送完所有的数据之后,给主动关闭方返回第二次应答之后进入到这个状态,表示被关闭方所有的消息也发送完成了。
CLOSED:主动关闭方在接收到消息第二次应答之后,并给被关闭方发送应答信息之后,等待2msl时间后进入到该状态,被动关闭方在接收到主动方关闭应答之后进入到该状态。
CLOSING:双方同时发送关闭请求的时候,双方都进入到FIN-WAIT-1状态之后,都受到了对方的关闭请求,则会进入到这个状态
同时发送关闭请求的情况
面试题
1.为什么是四次挥手
TCP属于全双工通信模式。双方都需要确认自己已经发送完消息可以关闭并需要得到对方的应答,所以最少需要两个来回来确定双方的消息都已经发送完毕并可以完成关闭。
2.客户端为什么需要在 TIME-WAIT 状态等待 2MSL 时间才能进入 CLOSED 状态?
如果被关闭端没有接收到主动关闭端的应答请求,则重试。而报文在网络中的最长存活时间是msl。等待2msl的原因就是给被关闭端重试的时间,如果这个时间内收到被关闭端又发送关闭请求的话,主动关闭端会再次发送应答并重新开始计时,保证被关闭端收到应答。
3.如何查看TIME-WAIT状态的连接数量
netstat -an |grep TIME_WAIT|wc -l (linux系统)
netstat -an |findstr TIME_WAIT (windows系统)
4.为什么会TIME_WAIT过多,解决方法是什么?
影响:大量占用端口,TCP 端口数量,上限是 6.5w(65535,16 bit)。大量 time_wait 状态存在,会导致新建 TCP 连接会出错,address already in use : connect 异常
可能的原因:高并发短链接的TCP服务器上,当服务器处理完请求后立即按照主动正常关闭连接。
解决:
1.负载均衡服务器;web服务器首先关闭来自负载均衡服务器的连接;(没理解,哪位大神帮助解答一下)
2.缩短TIME-WAIT状态的等待时间
3.如果可以设置连接的connection为keep-alive。