一、三次握手
-
为什么需要三次握手?
- 假设只有一次握手:客户端只发送了连接请求,就开始传输数据,这显然有问题,因为不知道服务端是否准备好接收数据。
- 假设只有二次握手:服务端收到了连接,并向客户端确认,如果没有收到客户端的确认,就向客户端发送数据,可能客户端还没准备好接收数据,而使发送失败。
三次握手是一个双向确认的过程,第一二次握手是客户端确认服务端是否有效的过程。第二三次握手,是服务端确认客户端是否有效的过程。只有确认对端有效才能申请系统资源,否则就是浪费资源。
-
SYN攻击
- 半连接:服务端发出第二次握手之后,客户端完成了对服务端的验证,此时服务端等待客户端的回复(第三次握手),此时被称为半连接。
- SYN攻击:大量的伪造客户端发起第一次握手,由于是伪造的客户端,服务端收不到第三次握手(此时就是半连接状态),然后会一直重传二次握手,会大量的消耗服务端资源。
- SYN攻击检测:半连接状态的服务端状态为SYN_RECV,只要检测服务器上是否有大量的SYN_RECV状态的连接就可以。
二、四次挥手
- 四次挥手存在的意义是要保证双端资源的正确释放、避免丢失数据。
- 第二次和第三次挥手在没有数据需要传递的情况下可以合并,此时也就没有了FIN_WAIT_2状态。
- 等2MSL的意义:
- 最后回复后,如果回复丢失,需要重传。
- MSL为报文最大生存时间,超过这个时间的报文会被丢弃。tcp连接是由某个程序发起的(占用端口)。假设前一个程序关闭连接时,另一个程序以相同的四元组建立连接,TCP无法区分前后两条TCP连接是不同的,然后新连接的通讯会失败(对端关闭)。等2MSL可以避免次情况
- TIME_WAIT 和CLOSE_WAIT状态socket过多
- TIME_WAIT:服务器连接过多,应该使用连接池,限制过多的短连接
- CLOSE_WAIT:被动关闭连接处理不当导致的。
- SO_REUSEADDR 选项
可以让TIME_WAIT状态连接,立即可以被使用,而不必等待2MSL
三、重传机制
-
tcp包都会一个seq序号,接收端收到包后需要确认回复ack=seq+1
-
接收端给发送端的ack确认只会确认最后一个连续的包,比如,发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,4,5 接收端要回ack 3,不能跳着回复
-
常见的重传机制
例子:发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,4,5- 超时重传:3 报文超过了设置的回复时间就会重传该包
- 快速重传机制:接收端一直回复3,超过三次,即使没超时,也会重传该包
上面重传方式会有一个问题: 4,5 接收端已经收到了,但是发送方不知道,所以4,5也会重传。可以用下方式解决
- SACK:在TCP 头部「选项」字段里加一个 SACK 字段记录已接收的包范围,ack=3,sack=4-5,等收到3后可以回复ack=6
- D-SACK:就是sack的另一个用处,用于解决ack确认丢失,导致数据重复。回复ack=6,然后丢失了,那么发送端仍然会认为3没有收到,而继续发3,当接收端收到3时,发现3已存在了,就会回复ack=6,sack=3,发送端就知道刚才是回复报文丢失了。
四、滑动窗口
- tcp 每发送一个包都需要确认,滑动窗口实现了批量发送和确认。
- tcp 头里有一个字段叫 Window,也就是窗口大小,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。所以,通常窗口的大小是由接收方的窗口大小来决定的。
- 流量控制:简单说就是接收端和发送端动态调整发送数据量和窗口大小的过程
五、拥塞控制
- 重传越严重,证明网络越拥塞,所以拥塞控制也会控制流量,tcp用拥塞窗口来控制流量。拥塞算法主要有四个
- 慢启动 :顾名思义,就是慢慢增加拥塞窗口的大小,即增加流量。当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1。
- 拥塞避免:当慢启动窗口大小到达了一个设定的阀值,就会降低增加的速度。每当收到一个 ACK 时,cwnd 增加 1/cwnd。例如,当 8 个 ACK 应答确认到来时,每个确认增加 1/8,8 个 ACK 确认 cwnd 一共增加 1
- 拥塞发生:当发生重传时,拥塞避免的阀值和拥塞窗口的值会降低
- 快速恢复:当发生超时重传时,可以让拥塞避免的阀值和拥塞窗口的值开始回复