HTTP相关
TCP协议
TCP 与 UDP 的区别
TCP是一个面向连接的、可靠的、基于字节流的传输层协议,而UDP是一个无连接的传输层协议
面向连接 所谓的连接,指的是客户端到服务器的连接,在双发的互相通信之前,TCP需要三次握手简历连接,而UDP没有简历连接的过程。
可靠性。TCP花了很多功夫保证连接的可靠性,一个是有状态,另一个是可控制。
- TCP会精准记录哪些数据发送了,哪些数据被接受了,哪些没有被接收到,而且保证数据包按顺序到达,不允许半点差错,这就是有状态
- 当意识到丢包或者网络环境不佳,TCP会根据具体情况调整自己的行为,控制自己的发送速度或者重发,这是可控制
相应的, UDP就是
无状态
,不可控
的面向字节流。UDP的数据传输时基于数据包的,这是因为仅仅继承了IP层的特性,而TCP为了维护状态,将一个个IP包变成了字节流
TCP的三次握手
- 最开始双方都处于
CLOSED
状态。然后服务端开始监听某个端口,进入了LISTEN
状态 - 客户端主动发起连接,发送 SYN,自己变成
SYN-SENT
状态 - 服务端收到之后返回
SYN
和ACK
(对应客户端发来的SYN),自己变成了SYN-REVD
- 客户端再发送
ACK
给服务端,自己变成了ESTABLESHED
状态; - 服务端收到
ACK
之后,也变成了ESTABLESHED
状态
令外需要注意的时,从图中可以看出,SYN 时需要消耗一个序列号的,下次发送的ACK序列号要加1,原因只需要记住一个规则
凡是需要对端确认的,一定小号TCP报文的序列号。
SYN需要对端的确认,而ACK并不需要,因此SYN消耗一个序列号而ACK不用。
TCP 四次挥手
- 刚开始双方处于
ESTABLESHED
状态 - 客户端要断开了,向服务器发送
FIN
报文 - 发送后客户端变成了
FIN-WAIT-1
状态,这时候客户端同事也变成了half-close(半关闭)
状态,无法向服务端发送报文,只能接收。 - 服务端接收后向客户端确认,变成了
CLOSED-WAIT
状态 - 客户端收到了服务端的确认,变成了
FIN-WAIT-2
状态 - 服务端向客户端发送
FIN
,自己进入LAST-ACK
状态 - 客户端收到服务端发来的
FIN
后,自己变成了TIME-WAIT
状态,然后发送ACK给服务端
这个时候,客户端需要等待足够长的时间,具体来说,时2个 MSL(Maximum Segment Lifetime, 报文最大生存时间)
,这段时间内如果客户端没有收到服务端的重发请求,那么表示 ACK 成功到达,挥手结束,否则客户端重发ACK。
为什么要等待2个MSL?因为如果不等待,一旦服务端还要给客户端发送数据包而客户端已经关闭并且客户端的端口被其他应用占用了,就会造成数据包混乱。
- 1个MSL确保四次挥手中主动关闭方最后的ACK报文最终能达到对端
- 1个MSL确保对端没有收到ACK重传的FIN报文可以达到
为什么是四次挥手
因为服务端在接手到 FIN
,往往不会立即返回 FIN
,必须等到服务端所有的报文都发送完毕了,才能发 FIN
。因此先发一个 ACK
表示已经收到客户端的 FIN
,延迟一段时间才发 FIN
。这就造成了四次挥手
半连接队列和 SYN Flood 攻击
三次我收钱,服务端的状态从
CLOSED
变为LISTEN
,同时在内部创建了两个队列:半连接队列和全连接队列,即SYN队列和ACCEPT队列。
半连接队列
当客户端发送SYN
到服务端,服务端收到以后回复ACK
和SYN
,状态由CLOSED
变为 LISTEN
,此时这个连接就被推入SYN队列,也就是半连接队列
全连接队列
低昂客户端返回ACK
,服务端接收后,三次握手完成。这个时候连接等待被具体的应用取走,在被取走之前,它会被推入另外一个TCP维护的队列,也就是全连接队列(Accept Queue)
SYN Flood攻击原理
SYN flood 属于典型的 DoS/DDoS攻击。其攻击原理很简单,就是用客户端在短时间内伪造大量不存在的IP地址,并向服务端疯狂发送SYN
。对于服务端而言,会产生两个危险的后果:
- 处理大量的
SYN
包并返回对应的ACK
,势必有大量连接处于SYN_RCVD
状态,从而沾满整个半连接队列,无法处理正常的请求 - 由于是不存在的IP,服务端长时间收不到客户端的
ACK
,会导致服务端不断重发数据,直到耗尽服务端你的资源
如何应对 SYN Flood 攻击
- 增加 SYN 连接,也就是增加半连接队列的容量
- 减少 SYN + ACK 重试次数,避免大量的超时重发
- 利用 SYN Cookie 技术,在服务端接收到 SYN 后不立即分配连接资源,而是根据这个 SYN 计算出一个Cookie,连同第二次握手回复给客户端,客户端在回复 ACK 的时候就会带上这个 Cookie,服务端验证 Cookie 合法后才分配连接