三次握手和四次挥手
1. 三次握手
1. 凉凉答题法
请介绍下三次握手
第一次握手就是客户端给服务端发送一个报文, 第二次就是服务器收到报文之后, 会应答一个报文给客户端, 第三次握手就是客户端收到报文后再给服务器发送一个报文
2. 三次握手
1. 定义
指建立一个TCP连接时, 需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小
信息。
1. 第一次握手
客户端给服务端发送一个SYN报文, 并指明客户端的初始化序列号ISN, 此时客户端处于SYN_SENT状态
首部的同步位SYN=1, 初始序列号seq=x, SYN=1的报文段不能携带数据, 但要消耗掉一个序号
2. 第二次握手
服务器收到客户端的SYN报文后, 会以自己的SYN报文作为应答, 并且也是指定了自己的初始序列化号ISN(s), 同时会把客户端的ISN + 1作为ACK的值, 表示自己已经收到客户端的SYN, 此时服务器处于SYN_RCVD状态
在确认报文中SYN=1, ACK=1, 确认号ack = x+1, 初始序列号seq=y
3. 第三次握手
客户端收到SYN报文后, 会发送一个ACK报文, 当然, 也是一样把服务器的ISN+1作为ACK的值, 表示已经收到了服务端的SYN报文, 此时客户端处于ESTABLISHED状态, 服务端收到ACK报文后, 也处于ESY=TABLISHED状态, 此时, 双方建立连接
确认报文段ACK=1, 确认号ack=y+1, (初始为seq=x,第二个报文段所以要+1), ACK报文段可以携带数据,不携带数据则不消耗序号。
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
在socket编程中,客户端执行connect()时,将触发三次握手。
3. 什么是半连接队列?
服务器第一次收到客户端的SYN之后, 就会处于SYN_RCVD状态, 此时双方还没有完全建立连接, 服务器会把此种状态下的请求连接放在一个队列里, 就叫做半连接队列
4. ISN(Initial Sequence Number)是固定的吗?
当一端为建立连接而发送它的SYN时, 它为连接选择一个初始序列号, ISN随时间的变化而变化, 因此每个连接都将具有不同的ISN, ISN可以看做是一个32比特的计数器, 每4ms加1, 这样选择序列号的目的在于防止网络中被延迟的分组在之后又被传送, 而导致某个连接一方对它做错误的解释
如果ISN是固定的, 攻击者很容易猜出后续的确认号, 因此ISN是动态生成的
5. SYN-ACK重传次数
服务器发送完SYN-ACK包, 如果未收到客户确认包, 服务器进行首次重传, 等待一段时间仍未收到客户确认包, 进行第二次重传, 如果重传次数超过系统规定的最大重传次数, 系统将该链接信息从半连接队列中删除
每次重传的时间不一定相同, 一般是指数增长, 1s, 2s, 4s, 8s,.....
6. 三次握手中可以携带数据吗?
第一次第二次不可以, 第三次可以携带
` 第一次还没有建立连接, 会让服务器更容易受到攻击, 第三次的时候客户端已处于ESTABLISHED状态, 对于客户端来说, 他已经建立起连接, 并且服务器的接收, 发送能力是正常
7. SYN攻击是什么?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstat 命令来检测 SYN 攻击。
常见的防御SYN攻击的方法:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
2. 四次挥手
1. 四次挥手的原因
这由TCP的半关闭造成的, 所谓半关闭, 其实就是TCP提供了连接的一端在结束它的发送还能接收来自另一端数据的能力
2. 四次挥手的过程
1. 第一次挥手
客户端发送一个FIN报文, 报文中会指定一个序列号, 此时客户端处于FIN_WAIT1状态
即发出连接报文释放段(FIN=1, 序号seq=u), 并停止再次发送数据, 主动关闭TCP连接, 进入FIN_WAIT1状态, 等待服务端的确认
2. 第二次挥手
服务端收到FIN后, 会发送ACK报文, 且把客户端的序列号值+1作为ACK报文的序列号值, 表明已经收到客户端等待报文了, 此时服务端处于CLOSE_WAIT状态
即服务端收到连接释放报文段后即发出确认报文段(ACK=1, 确认号ack=u+1, 序号seq=v), 服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。
3. 第三次挥手
如果服务端也准备断联, 和客户端的第一次挥手一样, 发送FIN报文, 且指定一个序列号, 此时服务端处于LAST_ACK状态
即服务端没有要向客户端发送的数据, 服务端发出连续释放报文段(FIN=1, ACK=1, 序号seq=w, 确认号ack=u+1), 服务端进入LAST_ACK状态, 等待客户端的确认
4. 第四次挥手
客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT
状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED
状态。
即客户端收到服务端的连接释放报文段后, 对此发出确认报文段(ACK=1, seq=u+1, ack=w+1), 客户端进入TIME_WAIT状态, 此时TCP未释放, 需要经过时间器设置时间2MSL后, 客户端才进入CLOSED状态
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
1. 挥手为什么需要四次?
当负服务端收到客户端的SYN连接请求报文时, 可以直接发送SYN+ACK报文, 其中ACK报文是用来应答的, SYN报文是用来同步的, 但是关闭连接时, 当服务端收到FIN报文时, 很可能并不会立即关闭SOCKET, 所以只能先回复一个ACK报文, 因此不能一起发送
2. 2MSL等待状态有什么意义?
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器
。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
原因1: 保证客户端发送的最后一个ACK报文能够达到服务端
原因2: 防止'已失效的连接请求报文段' 出现在新的连接中
3. 为什么TIME_WAIT状态需要经过2MSL才能回到CLOSE状态?
用来重发可能丢失的ACK报文
3. 补充
1. 重要字段
1.序号: seq序号, 占32位, 用来标识从TCP源端向目的端发送的字节流, 发起方发送数据时对此进行标记
2.确认号: ack序号, 占32为, 只有ACK标志为1时, 确认序号字段才有效, ack=seq+1
3. 标志位:
1. URG: 紧急指针有效
2. ACK: 确认序号有效(为了与确认号ack分开, 用大写表示)
3. PSH: 接收方应该尽快将这个报文交给应用层
4. RST: 重置连接
5. SYN: 发起一个新连接
6. FIN: 释放一个新连接
2. 重要字段的作用
seq序号、ack序号:用于确认数据是否准确,是否正常通信。
标志位:用于确认/更改连接状态。