参考文献:
三次握手
-
目的
-
确认接收和发送端的接收和发送能力正常
-
指定自己的初始化序列号,为后续的可靠传输做准备
-
如果是HTTPS协议的话,还会进行加密密钥的生成和数字证书的验证。
-
过程
- seq:sequance 序列号
- ack:acknowledge 确认号
- SYN:synchronize 请求同步标志
- ACK:acknowledge 确认标志
- FIN:Finally 结束标志
-
超时重传
当TCP发出一个报文段后,会启动重传计时器,一般设定为60s,当超过这个时间还未接受到应答,就会重发该报文段,
由于TCP传输能保证数据的可靠性也就是无差错,不丢失,不重复和有序。所以如果接收端接受到了重复的信息会舍弃。操作系统会设定一个重传的数量,一旦超出这个数量就会断开连接而不是继续重复发送这样可以避免被SYN泛洪攻击,也可以减少资源浪费。
-
半连接状态
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为
半连接队列。
当然还有一个
全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
-
三次握手的必要性
如果只有两次握手,假如第一次客户端发送的SYN的包延时了,又重发了一个序列号相同的SYN的包建立应有的连接,当这个连接结束以后,如果第一次延时的SYN的包到达了,服务器端会再次建立连接,但是客户端并没有要申请建立连接,所以就不会给服务器发送数据,这样服务器端就建立了一个空连接,白白浪费了资源。
TCP作为全双工通信,它需要两边都有独立的接收和发送能力
|
客户端
|
服务端
| ||||||
|
自己
|
接收端
|
发送端
|
自己
| ||||
|
发送
|
接收
|
发送
|
接收
|
发送
|
接收
|
发送
|
接收
|
一次握手
|
|
|
|
|
正常
|
|
|
正常
|
两次握手
|
正常
|
正常
|
正常
|
正常
|
正常
|
|
|
正常
|
三次握手
|
正常
|
正常
|
正常
|
正常
|
正常
|
正常
|
正常
|
正常
|
-
第三次ACK包丢失的问题
如果没有回应,另外一方会不停的补发相应的包,所以第一次和第二次丢包的以后,都是由客户端重新第一次握手,等于重头开始。但是如果第三次丢失ACK确认包也让服务器端不停的补发第二次的包的话,就会出现
SYN 泛洪攻击:
通过建立大量虚假IP去进行三次握手,然后故意不做第三次回复应答,这样服务器端就会不停的补发第二次的ACK包。导致服务器消耗大量内存资源和CPU最后死机。
当出现这种情况时,服务器会发送一个RST报文,然后进入CLOSE状态。这个RST报文
会把连接信息全部初始化,原有的TCP协议将无法再进行,如果想重新建立连接
只能从第一次握手开始。
-
第一次和第二次握手是不能携带数据的,但是第三次握手可以携带数据。
四次挥手
由于
TCP是全双工通信,所以断开连接需要两边单独关闭。这个原则是当一方完成数据发送任务以后就会发送一个FIN来终止这个方向的连接。收到一个FIN只是意味着这一方向上没有数据流动。一个TCP连接在收到一个FIN以后仍旧能发送数据,
首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
通俗概括为:
-
客户端:我要关闭连接了( FIN=1,seq=u)
-
服务端:你那边的连接可以关闭了( ACK=1,seq=v,ack=u+1)
-
服务端:我这边也要关闭连接了( FIN=1,ACK=1,seq=w,ack=u+1)
-
客户端:你那边的连接可以关闭了( ACK=1,seq=u+1,ack=w+1)
-
客户端(发送释放数据报文首部FIN并停止发送数据)[FIN-WAIT-1终止等待1] ———> 服务器
-
客户端 [FIN-WAIT-2终止等待2] <— — — 服务器(发送确认报文ACK) [CLOSE-WAIT关闭等待]
-
客户端 <— — — 服务器(发送连接释放报文FIN) [LAST-ACK最后确认]
-
客户端(发送确认报文ACK)[TIME_WAIT时间等待] — — — > 服务器
-
客户端经历过程
-
ESTABLISHED(已连接)
-
FIN-WAIT-1(终止等待1)
-
FIN-WAIT-2(终止等待2):在进入此状态之前还需要接受服务器发送的最后的数据。
-
TIME-WAIT(时间等待):等待2MSL(最长报文段寿命 Maximum Segment Lifetime)。
-
CLOSED(关闭)
-
服务器经历过程
-
ESTABLISHED(已连接):接收到释放报文以后会通知应用进程然后进入下一个阶段。
-
CLOSE-WAIT(关闭等待):此段时间内客户端已经没有数据要发送了,但是服务器发送的数据客户端依然要接受。
-
LAST-ACK(最后确认)
-
CLOSED(关闭)
可以看出,服务器结束TCP连接的时间比客户端要早。
之所以握手需要三次,挥手却需要四次,是因为TCP的半关闭状态导致的:
握手时,服务器接受到SYN请求后,返回ACK和SYN可以放在一个报文里发送,但是挥手时,接受到FIN后,它仅仅代表对方没有数据发送给你了,但是未必你所有的数据都全部发送给对方了。所以你不会马上关闭socket,你很有可能还有数据要发送给对面然后在发送你的请求释放报文FIN,这样就变成了四次。
-
如果最后一次ACK确认报文丢失
在第三步中,如果客户端收到了来自服务器的FIN报文,会设置一个计时器,最长等待时间也就是2MSL(最长报文段寿命)。如果第四次挥手的ACK报文丢失,服务器端会重置计时器并再次发送第三次挥手的FIN报文。但是如果超过了2MSL时间客户端还没有收到服务器的FIN报文就会自动关闭,变成CLOSE状态。这样服务器就永远无法获取到ACK确认报文了。
如果出现这种情况它会触发
TCP保活计时器。通常时间会设置为两个小时,如果两个小时没有收到客户端的信息,会每隔75s发送一次探测报文,如果连续发送10个报文客户端都没有响应,服务器会认为客户端出故障了,从而关闭自己。