TCP三次握手与四次挥手
TCP基本认识
TCP连接建立
第三次握手是可以携带数据的。
TCP建立连接时,三次握手 能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。
不使用 两次握手 的原因:
- 两次握手:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号。
为什么TCP层还需要MSS?
若TCP被MTU分片,仅第一个分片有TCP头部,接收方IP层只有重组了这些分片才会认为是一个TCP报文,交付给TCP层;因此,若丢失了一个分片,则需要超时重传整个TCP报文;
若TCP报文被MSS分片,那么每个分片都是具有TCP头部的TCP报文。
什么SYN攻击?如何避免SYN攻击?
攻击者短时间伪造不同IP地址的SYN报文,服务端发送ACK+SYN报文后,没有得到ACK应答; 久而久之就会占满服务端的SYN接受队列(半连接队列)。
避免SYN攻击方式一
修改Linux内核:
- 当网卡接收数据包的速度大于内核处理速度时,会有一个队列保存这些数据包;控制该队列的最大值。
- SYN_RCVD状态连接的最大个数;
- 超出处理能时,对新的SYN直接回报RST
避免SYN攻击方式二
TCP连接断开
为什么TIME_WAIT等于2MSL?
MSL是报文最大生存时间。 这其实相当于至少允许报文丢失一次;若ACK在1个MSL内丢失;这样被动方重发的FIN会在第2个MSL内到达。
2MSL是从客户端接收到ACK后发送ACK开始计时的。 若在TIME_WAIT内客户端的ACK没有传输到服务端,客户端又接收到了服务端重发的FIN报文,2MSL时间重新计时。
为什么需要TIME_WAIT?
- 防止旧连接的数据包
- 保证连接正确关闭
TIME_WAIT过多的危害?
-
内存资源占用
-
端口资源占用
- 客户端:一个TCP连接至少消耗一个本地端口
- 服务端:把连接扔给处理线程,所以理论上端口可以继续监听;但是线程池有限。
如何优化TIME_WAIT?
- 复用处于TIME-WAIT的socket为新的连接所用;
- 当TIME-WAIT连接数超过一定值后,将后面的TIME-WAIT连接重置
- 立刻发送RST标志给对端,该TCP连接将跳过四次挥手,也就跳过了TIME-WAIT。(但十分危险)
如果已经建立连接,客户端忽然出现故障?
保活机制
一定时间段内,若没有任何连接相关的活动;每隔一个时间间隔,发送一个探测报文;若连续几个探测报文没有得到响应,则认为该连接死亡。
若开启了TCP保活:
- 对端正常工作:对端正常响应,TCP保活时间被重置。
- 对端崩溃并重启:对端响应RST报文,TCP连接被重置。
- 对端没有响应:该连接已死亡。
Socket编程
服务端调用 accept 时,连接成功了会返回一个已完成连接的socket,后续用来传输数据; 所以,监听socket和已完成连接socket是两个socket。
TCP重传、滑动窗口、流量控制、拥塞控制
重传机制
超时重传
RTT是数据包的往返时间。RTO是超时重传时间。
实际上,RTT是经常变化的; 所以,RTO应该是一个动态变化的值。 估计RTO,通常需要采样:
- 采样RTT并加权平均,算出一个平滑RTT的值
- 采样RTT的波动范围
超时重发的数据再次超时,TCP的策略是超时间隔加倍。
快速重传
问题:是重传Seq2?还是重传Seq2、Seq3、Seq4、Seq5呢?
SACK
在TCP头部 选项 字段加一个SACK的东西,将缓存的地图发给发送方。
D-SACK
使用SACK来告诉发送方有哪些数据被重复接收。
ACK丢包
网络延时
滑动窗口
累计确认/累计应答
窗口大小由哪一方决定?
TCP头有一个字段:Window。
这个字段是接收方告诉发送方自己还有多少缓冲区接收数据。于是,发送方可以根据接收方的处理能力发送数据。
所以,窗口的大小是由接收方的窗口大小来决定。
发送窗口
接收窗口
接收窗口的大小约等于发送窗口的大小。 因为新的接收窗口大小是通过TCP报文的Windows字段告诉发送方的。 这个传输过程存在时延。
流量控制
操作系统缓冲区与滑动窗口的关系
上一张图,我们假定了发送窗口和接收窗口是不变的。
事实上,操作系统的缓冲区会影响发送和接收窗口。
发生了窗口关闭。
为了防止这种情况发生(窗口大小出现负值),TCP规定只能先收缩窗口,过段时间再减少缓存。
窗口关闭
窗口关闭的潜在危险
TCP是如何解决窗口关闭时潜在的死锁现象呢?
- 若接收窗口仍为0,发送方重启计时器。
窗口探测的次数一般为3次。若3次之后接收窗口仍为0,有的TCP实现就会发RST来中断连接。
糊涂窗口综合症
如果接收方腾出几个字节并告诉发送方,发送方也会义无反顾 发送这几个字节。TCP+IP头都有40字节,开销过大。
解决办法:
- 让接收方不通知小窗口
- 让发送方避免发送小数据
让接收方不通知小窗口
当 窗口大小 小于 min(MSS,缓存空间/2),即向发送方告知窗口为0;
让发送方避免发送小数据
使用Nagle算法,发送数据要满足以下两条中的一条:
- 当窗口大小或数据大小 >= MSS
- 收到之前发送数据的ACK包
拥塞控制
避免发送方的数据填满整个网络。
拥塞窗口cwnd:根据网络的拥塞程度动态变化。
- 网络中没有出现拥塞,cwnd增大;
- 网络中出现了拥塞,cwnd减少;
只要发生了超时重传,就认为网络出现了拥塞。
慢启动
拥塞避免
拥塞发生
拥塞发生,也就是会发生数据包重传:
- 超时重传
- 快速重传
发生超时重传的拥塞发生算法
太激进,会造成网络卡顿。
快速恢复
快速重传和快速恢复算法一般同时使用。