TCP 三次握手和四次挥手
TCP 全称是传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议。
连接是指各种设备、线路,或网络中进行通信的两个应用程序为了相互传递消息而专有的、虚拟的通信线路,也叫做虚拟电路。一旦建立了连接,进行通信的应用程序只使用这个虚拟的通信线路发送和接收数据,就可以保障信息的传输。应用程序可以不用顾虑提供尽职服务的 IP 网络上可能发生的各种问题,依然可以转发数据。TCP 则负责控制连接的建立、断开、保持等管理工作。
TCP 的建立连接就是靠三次握手,断开连接就是靠的四次挥手。
TCP 首部
先简单看一下 TCP 首部格式:
本文主要讲一下和三次握手、四次挥手有关的字段。
标志位
标志位就是窗口
字段前面的几个字段,每个字段只占 1bit。
- SYN(synchronous): 发送/同步标志,用来建立连接,和 ACK 标志位搭配使用。A 请求与 B 建立连接时,SYN=1,ACK=0;B 确认与 A 建立连接时,SYN=1,ACK=1
- ACK(acknowledgement):确认标志,表示确认收到请求
- PSH(push) :表示推送操作,就是指数据包到达接收端以后,不对其进行队列处理,而是尽可能的将数据交给应用程序处理
- FIN(finish):结束标志,表示关闭一个 TCP 连接
- RST(reset):重置复位标志,用于复位对应的 TCP 连接
- URG(urgent):紧急标志,用于保证 TCP 连接不被中断,并且督促中间层设备尽快处理
序列号(Sequence Number)和确认号(Acknowledge Number)
TCP 使用序列号
来记录发送数据包的顺序,TCP 传送一个数据包发送数据包时,需要带上此次报文段的序列号
,传送一个数据包后,只有在指定时间里收到这个包的确认信息,才会将其从队列中删除,否则会重新发送该数据包。TCP 接收到对方的数据包时,需要回传一个确认应答的报文,该报文首部 ACK 标志位
置 1,并且确认号
为下一次需要的报文段的序列号。
三次握手
三次握手过程:
文字描述:
- 假设 A 为客户端,B 为服务器端。
- 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
- A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
- B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
- A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
- B 收到 A 的确认后,连接建立。
为什么需要三次握手?
确认双方都有正常的发送能力和接收能力:
- 第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
- 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
- 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
确保服务器安全:如果只握手 2 次,那么意味着只要客户端发起一次请求即可以在服务打开一个连接,打开连接是需要消耗资源的,攻击者完全可以修改 IP 报文头部中的发送方 IP 地址,然后不停向服务端发起 TCP 连接请求(这也是 SYN 洪泛攻击 的原理)
如何检测和防范 SYN 洪泛攻击
检测:当在服务器上看到大量的半连接状态时,特别是源 IP 地址是随机的,基本上可以断定这是一次 SYN 攻击。
防范:使用 SYN cookie
,原理是将客户端的目的 IP 地址、端口号、序列号、一个密钥数用散列函数计算,将其作为第二次握手的序列号发送给客户端,此时服务端不需要记录该 cookie 和客户端的任何状态信息,如果客户端合法,将正常回传第三次握手,然后服务端再次计算SYN cookie
+ 1,和确认号相同则打开连接。
四次挥手
四次挥手过程:
文字描述:
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
- A 发送连接释放报文,FIN=1。
- B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
- 当 B 不再需要连接时,发送连接释放报文,FIN=1。
- A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
- B 收到 A 的确认后释放连接。
为什么要四次挥手?三次不行吗?
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
TIME_WAIT 为什么要等 2MSL
MSL 即报文最大生存时间(Maximum Segment Life),主要有两个原因:
确保最后一个确认报文能够到达
等待 2MSL 时间,即「FIN 报文 1MSL 传输 + ACK 报文 1MSL 超时」。如果 B 没收到 A 发送来的 ACK 报文,那么就会重新发送 FIN 报文,A 等待一段时间就是为了处理这种情况的发生。
防止已失效的连接请求报文段出现在之后的连接中
客户端在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。或者即使收到这些过时的报文,也可以不处理它。
参考资料