TCP(传输控制协议)通过三次握手建立连接,四次挥手终止连接,确保数据传输的可靠性。
TCP的三个控制标志位:
SYN——用于建立连接,同步序列号。
ACK——用于确认收到的数据。
FIN——用于终止连接。
ISN(Initial Sequence Number)——用于标识数据字节流的起始位置,确保数据传输的可靠性和顺序。(ISN是随便生成的)
应用程序 | FTP | TFTP | TELNET | SMTP | DNS | HTTP | SSH | MYSQL |
---|---|---|---|---|---|---|---|---|
熟知端口 | 21,20 | 69 | 23 | 25 | 53 | 80 | 22 | 3306 |
传输层协议 | TCP | UDP | TCP | TCP | UDP | TCP | TCP | TCP |
三次握手(建立连接)
第一次握手:
客户端向服务器发送SYN(同步)报文,其中包含客户端随机生成的初始序列号ISN=X,表示客户端请求与服务器建立连接。
第二次握手:
服务器收到SYN后,回复SYN-ACK报文,这个包中,服务器将自己的初始序列号设置为ISN=Y,同时将对客户端的确认号设置为ACK=X+1,表示服务器已经收到了客户端的 SYN 包,并且准备好与客户端建立连接。
第三次握手:
客户端收到SYN-ACK后,发送ACK报文,确认服务器的ISN。连接建立完成。该包的序列号为ISN=Y+1,确认号为ACK=Y+1,此时客户端和服务器连接建立成功,双方可以开始进行数据传输。
为什么是三次不是两次或者四次呢?
第一次握手:客户端发SYN包给服务器
此时服务器可得出结论:客户端发送能力正常,自己的接受能力正常。
第二次握手:服务器发SYN-ACK包给客户端
此时服务器可得出结论:自己的发送、接受能力正常,客户端的发送能力正常。
第三次握手:客户端发ACK包给服务器
此时服务器可得出结论:客户端发送、接受能力均正常,自己的发送、接受能力均正常。
因此,需要三次握手来确保客户端和服务器的发送与接受能力是否正常。
三次握手过程中可以携带数据吗?
通常第一次、第二次握手不可以携带数据,但是第三次握手时,可以携带数据。
这是由于在握手完成之前携带数据可能增加服务器负担,易受攻击。
什么是SYN攻击?
SYN 攻击是通过伪造大量 SYN 报文耗尽服务器资源,从而导致服务瘫痪。
在Linux上使用系统自带的 netstat 命令来检测SYN攻击:
netstat -n -p TCP | grep SYN_RECV
常见防御措施有如下几种:
- SYN Cookie:服务器不立即分配资源,而是生成 SYN Cookie 作为初始序列号,收到 ACK 后再分配资源。
- 增加队列大小:通过调整
net.ipv4.tcp_max_syn_backlog
参数扩大半连接队列。 - 减少超时时间:通过调整
net.ipv4.tcp_synack_retries
参数减少 SYN-ACK 重试次数。 - 防火墙过滤:配置防火墙规则,过滤异常流量或限制单个 IP 的连接数。
- 负载均衡:使用负载均衡设备分散流量,减轻单台服务器压力。
【拓展】
半连接队列——存放未完成三次握手的连接。服务器收到客户端的 SYN 报文后处于SYN-RCVD状态,将该连接请求放入半连接队列,等待客户端的 ACK 确认。
全连接队列——存放已完成三次握手、等待应用层处理的连接。
四次挥手(终止连接)
第一次挥手:
客户端向服务器发送FIN(结束)报文,其中包含序列号ISN=U,表示客户端希望关闭连接,此时客户端进入FIN_WAIT1状态。
第二次挥手 :
服务器收到FIN后,发送ACK报文,确认号为ACK=U+1,序列号为ISN=V,表示服务器已经收到了客户端的关闭请求,但服务器可能还有数据未发送完,此时服务器进入CLOSE_WAIT状态,客户端收到 ACK 包后进入FIN_WAIT2状态
第三次挥手:
当服务器完成数据发送后,会向客户端发送一个 FIN 包,序列号为ISN=W,确认号为ACK=U+1,表示服务器也准备关闭连接,此时服务器进入LAST_WAIT状态。
第四次挥手:
客户端收到服务器的 FIN 包后,会发送一个 ACK 包进行确认,确认号为ACK=W+1,序列号为ISN=U+1,客户端进入TIME_WAIT状态。服务器收到 ACK 包后,连接正式关闭,进入CLOSED状态。客户端在TIME_WAIT状态等待一段时间(通常为 2MSL,MSL 是最长报文段寿命)后,也会进入CLOSED状态。
为什么是四次挥手?
因为 TCP 是全双工协议,双方需要独立关闭各自的连接。
第一次挥手:客户端发送FIN包
此时的客户端表示:我不再发数据给你了哟
第二次挥手:服务器发送ACK包
此时的服务器表示:好的我知道了!
第三次挥手:服务器发送FIN包
此时的服务器表示:数据已经全部发给你了,我也不再给你发数据了哟
第四次挥手:客户端发送ACK包
此时的客户端表示:收到!停止连接!
因此,需要四次挥手来确保数据传输完整性和可靠性。
为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?
因为需要确保服务器收到 ACK,确保网络中旧数据段消失,防止旧数据干扰新连接。
总结
三次握手:SYN → SYN-ACK → ACK,确保双方准备好通信。
四次挥手:FIN → ACK → FIN → ACK,确保双方数据发送完毕并安全关闭连接。