欢迎光临散文网 会员登陆 & 注册

记录 - 5.2

2023-05-03 10:46 作者:剑离我离  | 我要投稿

mysql

round函数: 四舍五入,保留小数。

TCP 延迟确认与Nagle算法

  • Nagle 算法 :   满足任一条件

    • 条件一 : 要等到窗口大小  >= MSS并且数据大小 >= MSS

    • 条件二:收到之前发送数据的ack回包

  • 延迟确认:

  • 当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方

  • 当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送

  • 如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK

tcp_retries1 和tcp_retries2

两者都是在TCP 三次握手之后的场景

  • 当重传次数超过tcp_retries1就会指示IP 层进行MTU 探测、刷新路由等过程,并不会断开TCP 连接,当重传次数超过 tcp_retries2 才会断开TCP 流。

  • tcp_retries1 和tcp_retries2 两个重传次数都是受一个timeout 值限制的,当重传时间超过timeout,就不会重传了。

查看全连接队列

在listen状态时:

  • Recv-Q:当前全连接队列的大小,也就是当前已完成三次握手并等待服务端 accept() 的 TCP 连接;

  • Send-Q:当前全连接最大队列长度,上面的输出结果说明监听 8088 端口的 TCP 服务,最大全连接长度为 128

在非listen状态时:

  • Recv-Q:已收到但未被应用进程读取的字节数;

  • Send-Q:已发送但未收到确认的字节数;

当TCP  全连接队列满了会使用什么策略来回应客户端?

默认丢弃,也可以回复Rst复位报文。 通过 ipv4.tcp_abort_on_overflow 参数控制。0: 丢弃。 1:发送RST

如何增大TCP 全连接队列

TCP 全连接队列的最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)

半连接队列的大小

连接队列的最大值是 max_qlen_log 变量,半连接队列最大值不是单单由 max_syn_backlog 决定,还跟 somaxconn 和 backlog 有关系。

三次握手性能的提升

SYN_SENT、SYN_REV:

可以调整重传次数。如在内网中通讯时,适当调低重传次数,尽快把错误暴露给应用程序。

四次挥手的性能提升

关闭的方式:RST 报文和FIN 报文

如果进程收到RST 报文,直接关闭连接,这是一个暴力关闭连接的方式

close函数:关闭双向。

shutdown函数:优雅关闭,可以只关闭一个方向

FIN_WAIT1 状态的优化

重发由 tcp_orphan_retries参数控制:orphan 虽然是孤儿的意思,该参数却不只对孤儿连接有效,事实上,它对所有 FIN_WAIT1 状态下的连接都有效,默认值是 0。 0,特指 8 次。

对于普遍正常情况时,调低 tcp_orphan_retries 就已经可以了。如果遇到恶意攻击,FIN 报文根本无法发送出去,这由 TCP 两个特性导致的:

  • 首先,TCP 必须保证报文是有序发送的,FIN 报文也不例外,当发送缓冲区还有数据没有发送时,FIN 报文也不能提前发送。

  • 其次,TCP 有流量控制功能,当接收方接收窗口为 0 时,发送方就不能再发送数据。所以,当攻击者下载大文件时,就可以通过接收窗口设为 0 ,这就会使得 FIN 报文都无法发送出去,那么连接会一直处于 FIN_WAIT1 状态。

解决方法:调整 tcp_max_orphans 参数,它定义了「孤儿连接」的最大数量。超出数量的将会直接发送RST报文强制关闭。

FIN_WAIT2 状态的优化

close关闭的连接,不会在FIN_WAIT2持续太久,tcp_fin_timeout 控制此时长,默认是60s,这与TIME_WAIT的时间是一样的。

但shutdown可以在这个状态持续,因为可能还可以发送或接收数据。

TIME_WAIT 状态的优化

  1. 当TIME_WAIT 连接超过一定量(tcp_max_tw_buckets)时,新关闭的连接就不再经历TIME_WAIT 而直接关闭。

  2. 连接复用。打开tcp_tw_reuse 参数和打开时间戳功能。此参数只适用于连接发起方。

如何连接双方同时关闭连接,会怎么样?

双方在等待 ACK 报文的过程中,都等来了 FIN 报文。这是一种新情况,所以连接会进入一种叫做 CLOSING 的新状态,它替代了 FIN_WAIT2 状态。接着,双方内核回复 ACK 确认对方发送通道的关闭后,进入 TIME_WAIT 状态,等待 2MSL 的时间后,连接自动关闭。

开启时间戳的好处

  • 2MSL的问题不存在在了,因为重复的数据包会因为时间戳过期被自然丢弃

  • 可以防止序列号绕回

  • 便于精确计算RTT

传输性能的提升

如何确定最大的传输速度?

带宽时延积 BDP = RTT * 带宽

如果飞行报文超过了1MB,就会导致网络过载容易丢包。

怎样调整缓冲区大小

Linux 会根据设置的参数进行动态调节。

发送缓冲区是自行调节的,接收缓冲区可以根据系统空闲内存的大小来调节接收窗口。

发送缓冲区的调节功能是自动发开启的,而接收缓冲区则需要手动来开启调节功能。

小结

TCP 可靠性是通过 ACK 确认报文实现的,又依赖滑动窗口提升了发送速度也兼顾了接收方的处理能力。

内核缓冲区决定了滑动窗口的上限,缓冲区可分为:发送缓冲区 tcp_wmem 和接收缓冲区 tcp_rmem。

Linux 会对缓冲区动态调节,我们应该把缓冲区的上限设置为带宽时延积。发送缓冲区的调节功能是自动打开的,而接收缓冲区需要把 tcp_moderate_rcvbuf 设置为 1 来开启。其中,调节的依据是 TCP 内存范围 tcp_mem。

如何理解TCP 是面向字节流的协议

UDP: 操作系统不会对消息进行拆分,每个报文就是一个用户消息的边界。

TCP:不能认为一个用户消息对应一个TCP 报文,因此,TCP是面向字节流的协议。

为什么TCP 每次建立连接时,初始化序列号都要不一样呢?

防止历史数据被下一个相同的四元组错误的接收。

四次挥手的TIME_WAIT 不是会持续2MSL时长,历史报文不是早就在网络中消失了吗?

并不是所有连接都会通过四次挥手来正常关闭连接。

序列号回绕问题:

开启TCP时间戳。防回绕算法:要求双方维护最近一次收到数据包的时间戳,每收到一个新数据包都会跟上一个时间戳比较,如果发现时间戳不是递增的,则该数据包是过期的,直接丢弃该数据包。

如果时间戳也回绕了怎么办?

Linux 在 PAWS 检查做了一个特殊处理,如果一个 TCP 连接连续 24 天不收发数据则在接收第一个包时基于时间戳的 PAWS 会失效,也就是可以 PAWS 函数会放过这个特殊的情况,认为是合法的,可以接收该数据包。

SYN 报文什么情况下会被丢弃

  • 开启 tcp_tw_recycle 参数,并且在 NAT 环境下,造成 SYN 报文被丢弃

  • TCP 两个队列满了(半连接队列和全连接队列),造成 SYN 报文被丢弃

已建立连接的TCP ,收到SYN会发生什么

  1. 客户端的SYN 报文里的端口号与历史连接的不相同:

  • 服务端会认为是新的连接要建立,于是就会通过三次握手来建立新的连接。

旧连接处于 Established 状态的服务端最后会怎样呢?

  • 如果服务端发送了数据包给客户端,由于客户端的连接已经被关闭了,此时客户的内核就会回 RST 报文,服务端收到后就会释放连接。

  • 如果服务端一直没有发送数据包给客户端,在超过一段时间后,TCP 保活机制就会启动,检测到客户端没有存活后,接着服务端就会释放掉该连接。

  1. 客户端的 SYN 报文里的端口号与历史连接相同

处于Established 状态的服务端,如果收到了客户端的SYN 报文(SYN报文的初始化序列号是一个随机数,对于服务端就是一个乱序的序列号),会回复一个携带了正确序列号和确认号的ACK 报文,这个ACK 又称为 Challenage ACK ;

接着,客户端收到这个Challenage ACK ,发现确认号(ack  num)并不是自己期望收到的,于是会回复RST 报文,服务端收到后,就会释放该连接。

如何关闭一个TCP 连接

杀掉进程。

killcx 工具

它会主动发送 SYN 包获取 SEQ/ACK 号,然后利用 SEQ/ACK 号伪造两个 RST 报文分别发给客户端和服务端,这样双方的 TCP 连接都会被释放,这种方式活跃和非活跃的 TCP 连接都可以杀掉。

tcpkill 工具

在双方进行 TCP 通信时,拿到对方下一次期望收到的序列号,然后将序列号填充到伪造的 RST 报文,并将其发送给对方,达到关闭 TCP 连接的效果。

总结

  • tcpkill 工具只能用来关闭活跃的 TCP 连接,无法关闭非活跃的 TCP 连接,因为 tcpkill 工具是等双方进行 TCP 通信后,才去获取正确的序列号,如果这条 TCP 连接一直没有任何数据传输,则就永远获取不到正确的序列号。

  • killcx 工具可以用来关闭活跃和非活跃的 TCP 连接,因为 killcx 工具是主动发送 SYN 报文,这时对方就会回复 Challenge ACK ,然后 killcx 工具就能从这个 ACK 获取到正确的序列号。

在 FIN_WAIT_2 状态下,是如何处理收到的乱序到 FIN 报文,然后TCP连接又是什么时候才进入到TIME_WAIT 状态?

在FIN_WAIT_2状态时,如果收到乱序的FIN 报文,那么就会加入到乱序队列,并不会进入到TIME_WAIT 状态。

等收到前面被网络延迟的数据包时,会判断乱序队列有没有数据,然后会检测乱序队列中是否有可用的数据,如果能在乱序队列中找到与当前报文的序列号保持顺序的报文,就会看该报文是否有FIN 标志,如果发现有FIN 标志,这时才进入TIME_WAIT 状态。

在TIME_WAIT 状态的TCP 连接,收到SYN 后会发生什么?

  • 合法 SYN

  • 客户端的 SYN 的「序列号」比服务端「期望下一个收到的序列号」要并且 SYN 的「时间戳」比服务端「最后收到的报文的时间戳」要

  • 结果:重用此四元组连接,跳过2MSL 而转变为SYN_RECV状态。

  • 非法 SYN

  • 客户端的 SYN 的「序列号」比服务端「期望下一个收到的序列号」要或者 SYN 的「时间戳」比服务端「最后收到的报文的时间戳」要

  • 结果:会再回复一个第四次挥手的 ACK 报文,客户端收到后,发现并不是自己期望收到确认号(ack num),就回 RST 报文给服务端

在 TIME_WAIT 状态,收到 RST 会断开连接吗?

  • 如果 net.ipv4.tcp_rfc1337 参数为 0,则提前结束 TIME_WAIT 状态,释放连接。

  • 如果 net.ipv4.tcp_rfc1337 参数为 1,则会丢掉该 RST 报文。

进程崩溃和主机宕机

客户端主机宕机,又迅速重启

客户端没重启完:不会响应报文;重启完后,收到之前的TCP报文,都会回复RST报文。是否有进程绑定该TCP目标端口号,TCP维护的结构信息都已经丢失了,只能重新建立连接。

如果「客户端进程崩溃」,客户端的进程在发生崩溃的时候,内核会发送 FIN 报文,与服务端进行四次挥手。

但是,「客户端主机宕机」,那么是不会发生四次挥手的,具体后续会发生什么?还要看服务端会不会发送数据?

  • 如果服务端会发送数据,由于客户端已经不存在,收不到数据报文的响应报文,服务端的数据报文会超时重传,当重传总间隔时长达到一定阈值(内核会根据 tcp_retries2 设置的值计算出一个阈值)后,会断开 TCP 连接;

  • 如果服务端一直不会发送数据,再看服务端有没有开启 TCP keepalive 机制?

  • 如果有开启,服务端在一段时间没有进行数据交互时,会触发 TCP keepalive 机制,探测对方是否存在,如果探测到对方已经消亡,则会断开自身的 TCP 连接;

  • 如果没有开启,服务端的 TCP 连接会一直存在,并且一直保持在 ESTABLISHED 状态。

linux命令

netstat

  • -a--all :显示侦听套接字和非侦听套接字。

  • -t--tcp:只显示tcp套接字。

  • -u--udp:只显示udp套接字。

  • -l--listening :只显示侦听套接字。

  • -n--numeric:显示数字地址,而不是尝试确定符号主机、端口或用户名。

  • -p--program:显示每个套接字所属的程序的PID和名称。

  • -r--route:显示内核路由表。

  • -s--statistics:显示每个协议的汇总统计信息。 


记录 - 5.2的评论 (共 条)

分享到微博请遵守国家法律