Skip to content

Releases: Kylin010/tcpfit

v0.5.6

Choose a tag to compare

@Kylin010 Kylin010 released this 14 Aug 03:06

主要修复

测速偶发偏低会把整形值压到实际带宽的三分之一

一台 40 Mbps 的香港机器跑向导,近端 iperf3 三次里有一次掉到 13 Mbps。旧版本直接采信这一次读数,扫描区间被整个钉死在 25 以下,最终持久整形到 12 Mbit,国际接收只剩约 10 Mbps。

现在:不限速单流结果低于自动探测带宽的 70% 时,会在同一个对端追加两次测试,三次取送达量最高的那一组。取的是整组结果 —— 发送量、接收量、重传、丢包必须来自同一次测试,不会互相串。

三次都低也不会中断、不会换对端,继续按原有逻辑找拐点。首轮就达到 70% 的机器不增加任何运行时间。

对照(标称 40 Mbps,单流一次读到 13.0 / 34.5% 丢包,真实水平 37.4):

旧版本   采信 13.0  ->  扫描 12..25 档  ->  没找到可用拐点
本版本   补测 37.4 / 37.0  ->  取 37.4  ->  丢包 0.0000%
                          ->  判定无限速器, 一档都没扫, 不下整形

一键调优跑完不再自动回主菜单

调优要跑十几分钟,结果页面是唯一要看的东西。之前跑完停在「按任意键返回」,回菜单会清屏,而清屏指令连滚动回滚缓冲一起清掉 —— 往上翻也找不回结果。

现在一键调优跑完直接退出,结果留在屏幕上。要继续操作重新运行 tcpfit 即可。

「按任意键返回」不再被误触发

调优期间随手按的键会留在终端缓冲里,跑完的瞬间就把提示符吃掉,结果一眼没看见就回了菜单。现在会先清掉这些残留按键,只有真正按键才返回。

退出时也会一并清掉 —— 否则这些残留会被上层 shell 当成命令执行。


更新

tcpfit update

或在菜单中选择 8。更新后重新运行一次 tcpfit

首次安装

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

v0.5.5

Choose a tag to compare

@Kylin010 Kylin010 released this 13 Aug 21:24

主要修复

多队列网卡(10G / 多核大机器)的整形与恢复

10G 机器开机后的默认结构是 mq + 每个硬件队列一个 fq。这类网卡上:

  • 之前 tc qdisc del dev eth0 root 会直接失败(Cannot delete qdisc with handle of zero.),扫描和整形都装不上
  • 取消整形(shape --off)会把 mq 压成单个 fq,8 个硬件队列退化成一把锁
  • 恢复时不再把多队列网卡压成单 root fq,而是保留 mq 只替换它自己的叶子

已在真实 8 队列 10G 网卡上验证:扫描、整形、取消整形、保存/恢复四条路径全部正常,clsact(eBPF)不受影响。

小带宽机器:很浅的限速点不再被当成线路底噪吞掉

真实限速器的第一层损失可以只有 0.18%。旧逻辑会把这种浅损失当成"链路本身的噪声",于是错过真正的拐点,最后给出偏高的整形值。

300M 机器实测(4 轮换序,每档 15 秒冷却):

316M  0.0003%      319M  0.1911%   ← 真正的拐点在这里
317M  0.0003%      320M  0.4352%
318M  0.0006%      322M  1.0125%

现在遇到首档就丢包时,会向下测控制点来区分「真拐点」和「路径底噪」,最多三次;宁可不给整形值,也不把仍在丢包区的值推荐给你。

低带宽机器升级后会清掉旧版本的 initcwnd

100M 以下的机器保留内核默认的初始拥塞窗口。之前版本设置的 initcwnd 32 会被主动清除(包括开机自动写回的 hook)。

三台 10-20M 实机的对照:initcwnd 32 会导致首秒暴冲后被限速器打穿,之后每秒吞吐都掉一档,重传是默认值的 3-5 倍。

只清除 tcpfit 自己设过的;用户手工设的不动。

其他

  • 扫描第一档前增加 15 秒冷却。不限速探测会把限速器的令牌桶抽干,之前 3 秒不够回,导致第一档带着假丢包,进而污染整个扫描的判断基线
  • HTB 令牌桶按速率推算。2G/7G 机器接收吞吐提升 0.5~2.3%,1G 以下无差别
  • 缓冲区上限增加 2MiB 余量
  • 大带宽扫描保护:单流结果可疑时补测 8 流,避免误扫超出上限的区间

更新

tcpfit update

或在菜单中选择更新。更新后需要重新运行一次 tcpfit 才会用上新版本。

首次安装:

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

v0.5.4

Choose a tag to compare

@Kylin010 Kylin010 released this 11 Aug 06:46

主要修复:向导误报「本机没有 IPv4」导致流程中断

现象

跑向导时屏幕出现:

本机没有 IPv4, 测速走 IPv6

但机器明明有 IPv4,也没有 IPv6。随后走到「对端 IP」那一步直接退出:

公共测速服务器暂时都不可用, 稍后再试

测速服务器是好的,是脚本自己把协议族选错了。

什么样的机器会中

1 核 VPS + 有第二块网卡(最常见是用 Docker 装的面板留下的 docker0)。
两台客户机实测中招率 96%99%;2 核约 1%(偶发,重跑一次就好,但现象一模一样,最难排查);4 核以上基本不会。

和发行版无关 —— Debian 11 / 12、Ubuntu 都复现;在同一台机器上换 iproute2 5.9 / 5.15 / 6.1 三个版本,也都复现。

根因

脚本顶部是 set -uo pipefail,而 have_ipv4 写成 ip … | grep -q 'inet '
grep -q 一匹配就退出并关掉管道,写端 ip 还没写完就吃 SIGPIPE 被杀(退出码 141),pipefail 把 141 当成整条管道的返回值——「匹配到了」被读成「没匹配到」

只有匹配成功时才会触发,所以表现为「机器真的有 IPv4 → 报没有 IPv4」。
此外旧版判不出 v4 就无条件切 IPv6,从头到尾没检查过机器有没有 IPv6。

改动

  • 全脚本 14 处 | grep -q 清零,改用命令替换 + case(26 个用例差分测试确认行为等价)
  • have_ipv4 / have_ipv6 增加 ip route get 兜底 —— 默认路由不一定叫 default,机器上跑 VPN / 透明代理时常被拆成 0.0.0.0/1 + 128.0.0.0/1 或挪进策略路由表
  • 切 IPv6 前必须先确认 IPv6 可用;两边都判不出来时保持 IPv4 并明确说明

小带宽机器(100 Mbps 以下)现在能正常调优了

三台 10-20 Mbps 的机器上,旧版 9 次扫描全部失败。四个原因:

  • probe_bandwidth 把结果取整到 50 的档位,10 Mbps 直接归零 → 向导打印 Measured ~0 Mbps 后退出
  • 扫描步长硬下限 20,而小机器的扫描区间可能只有十几宽 → 只能采到 2 个点,找不到限速点
  • 扫描区间用 iperf3 发送端数字推算,丢包链路上它远高于实际送达量 → 起点直接落在丢包区
  • 安全余量对 100M 以下一律退 5 —— 15 Mbps 的线会被限到 10,白丢三分之一

现已分别修正:取整粒度跟档位走、步长按区间宽度推、区间改用实测送达量、余量按比例分档(≤30M 退 1、31-60M 退 2)。


其他修复

  • 整形值为整千时验证误判 —— tc 会把 1000 显示成 1Gbit,旧的解析剥不掉单位,导致跳过达成率判断。速率解析已统一成一个公共函数,11 个档位实测通过
  • 机器没装 ping 时甩锅测速服务器 —— 现在直接说明缺什么、怎么装;向导也会单独检查并询问安装(此前只在安装 iperf3 的分支里问,装了 iperf3 却没 ping 的机器永远问不到)
  • 重复跑向导时的整形残留 —— 这次没测到限速器时会主动清掉上次的限速;结果页和 verify 改为读取网卡实际状态,不再出现「屏幕写未设置、网卡上还挂着旧值」
  • 扫描过程中的 qdisc 残留 —— 修复扫描结束后 HTB 仍留在网卡上、屏幕却打印 qdisc restored 的问题

更新方式

tcpfit update

或在菜单中选择更新。更新后需要重新运行一次 tcpfit 才会用上新版本。

首次安装:

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

v0.5.3

Choose a tag to compare

@Kylin010 Kylin010 released this 10 Aug 04:26

RTT 不再探测,改用固定值

以前算缓冲区要先 ping 五个国内 DNS 测「到中国的延迟」。这一步现在去掉了,直接用 150ms。

为什么去掉:

一、测出来的值经常是错的。 那五个目标里,腾讯、百度、CNNIC 三个是 anycast —— 会命中离你最近的节点。实测一台香港机器:这三个报 1-2ms,而真正的国内线路是 138-145ms,差 70 倍

算小了之后缓冲区掉到 4MB 下限,而 4MB 正好是 Linux 的出厂值 —— 等于调了个寂寞,脚本还会打印一份看起来完全正常的推导过程。实测一台 2G 口的机器因此被摁在 100-220 Mbps。

二、有些机器根本测不了。 精简系统镜像不带 ping,有些机房挡 ICMP。这两种情况都会让脚本停在「无法确定 RTT,请用 --rtt 指定」—— 而向导里根本没地方填这个参数。

三、「到中国的延迟」本来就不是一个数。 同一台机器同一时刻实测:移动 55ms、联通 93ms、电信 138ms、上海电信 145ms,差 2.6 倍,晚高峰还要再拉开。测出来的只是这个分布里随机的一个点。

为什么是 150

缓冲区取 2 倍 BDP,所以填 150 能全速覆盖到 300ms 以内的路径。大陆用户的场景全在里面:

线路 延迟 覆盖
香港/新加坡优化线 40-70ms
香港普通线 145ms
美西 160-180ms
欧洲 / 美东 230-250ms
晚高峰拥塞 300ms

再往上没有收益:小内存机器会先被内存上限接住(512MB 封顶 16MB),填 150 还是 300 结果一样;大机器上则要多付代价 —— 实测缓冲区超配到 215 倍时,吞吐反而掉 22%。

知道自己真实延迟的,可以自己填

tcpfit tune --role proxy --bw 500 --rtt 250

比如你的机器在欧洲、用户在国内,实测 250ms,填进去比默认更准。这个参数以前没有校验(填错会掉进那条误导性报错),现在会明确提示。

顺带

tune 从此不再需要 ping 命令。

升级

菜单 8,或者:

tcpfit update

安装

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

校验

6c86b31c3d937736bb4d919b04b732013cbb2da958d97841b34cd663fd2a6b35  tcpfit.sh
8a521bcc2f89c336fba239d7b722cede8638ac9df06b28eb8be1536a22fd5085  install.sh

v0.5.2

Choose a tag to compare

@Kylin010 Kylin010 released this 10 Aug 03:52

必修:选 IPv6 会崩在「无法确定 RTT」

如果你在开头那一问选了 v6,接着看到:

[+] Measured ~1150 Mbps
[x] 无法确定 RTT, 请用 --rtt 指定

这是 v0.5.0 引入的问题,跟你的机器无关,本版修好了。

原因:算缓冲区要用「到国内的延迟」,而这个延迟不该跟着测速协议族走 —— 你选 v6 只是为了测对端,业务流量可能还走 v4。v0.5.0 错误地把它绑在一起,导致选 v6 之后延迟探测必然失败。

临时绕过(不想升级的话):那一问选 v4(直接回车就是)。

纯 IPv6 机器现在能找到网卡了

只有 IPv6 的机器之前会停在「找不到默认路由网卡」—— 这个从 v0.4.5 及更早就存在,一直没跑起来过。

手填 IPv6 对端地址不再被拆错

之前填 2001:db8::1 会被按最后一个冒号拆成「主机 2001:db8: + 端口 1」,然后拿着错的地址继续跑,一句提示都没有。

现在这六种写法都能正确识别:

1.2.3.4              example.com
1.2.3.4:5202         example.com:5202
2001:db8::1          [2001:db8::1]:5202

端口填错会当场重问,不再静默接受。

纯 IPv4 机器不再看到「检测不到 IPv4」

之前这句是无条件打印的说明文字,但纯 IPv4 机器(绝大多数)只看得到这一行,容易误以为脚本没认出自己的 IPv4。现在纯 v4 机器不再显示这句。

升级

菜单 8,或者:

tcpfit update

安装

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

校验

3aa22fad6e0d954a63d292c9cd1368b67d7c7c2c0ee95b7f0368781e8b6912fc  tcpfit.sh
8a521bcc2f89c336fba239d7b722cede8638ac9df06b28eb8be1536a22fd5085  install.sh

v0.5.1

Choose a tag to compare

@Kylin010 Kylin010 released this 10 Aug 02:49

重要:如果你更新到 v0.5.0 后发现问题依旧,不是修复没用

更新完请退出 tcpfit 再重新进一次。

v0.5.0 及之前的版本有个问题:菜单里按 8 更新,新版本确实写进磁盘了,但当前这个进程内存里跑的还是旧代码。而更新完的提示写着「想让新版参数生效,重跑一次调优」,用户很自然就在同一个菜单里按 1 —— 跑的仍然是旧版本,于是「更新了但 bug 还在」。

已经更新过的:直接退出、重新运行 tcpfit 就好,不用重新下载。

本版修复

更新后自动用新版本重启

菜单里更新完会自己换成新版本重开;命令行 tcpfit update 则明确提示当前进程仍是旧代码、需要重新运行。

更新时不再原地覆盖正在运行的脚本

之前是直接覆写 /usr/local/bin/tcpfit,而那正是当时正在执行的文件。改成先写临时文件再原子替换,正在运行的进程不受影响。

升级

菜单 8,或者:

tcpfit update

安装

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

校验

a1960b8042b667571575b7bf374485b2c2420f04501a32f999b73339a4724085  tcpfit.sh
8a521bcc2f89c336fba239d7b722cede8638ac9df06b28eb8be1536a22fd5085  install.sh

v0.5.0

Choose a tag to compare

@Kylin010 Kylin010 released this 10 Aug 02:29

修复:部分机房封了 5201,脚本会找不到任何测速对端

有机房为防止有人用 iperf3 刷流量,封掉了出站 5201(iperf3 的默认端口)。在这种机器上,脚本会把全部 18 个节点报成 port closed,最后提示「公共测速服务器暂时都不可用,稍后再试」—— 但服务器好好的,换个端口就能用。

现在选对端时会自动轮换 5201 → 5202 → 5203 → 5200,找到能用的就继续,界面上会显示 5201→5202 告诉你端口变了。第一个节点探出可用端口后,其余节点直接复用,不会拖慢。

如果你之前遇到「所有节点都 port closed」,升级即可。

顺带补上 Clouvider 节点的 5200 —— 他们开的是 5200-5209 而不是 5201-5210,之前那两个节点有一个实例一直没被用到。

新增:IPv4 / IPv6 协议族选择

  • 默认走 IPv4
  • 检测不到 IPv4 时自动走 IPv6
  • 双栈机器会在开头问一句,回车 = v4
  • tcpfit sweep 支持 -4 / -6 指定

同一个对端在两个协议族下延迟可能差很多(实测见过 v4 133ms / v6 308ms)。现在 ping 和 iperf3 锁定同一个协议族,不会出现「按 v6 的延迟挑节点、却用 v4 测速」这种情况。

升级

菜单 8,或者:

tcpfit update

安装

bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)

校验

b28752b7efad9e7ae3615f7c8c190a809733568ede5b05cdf39e49621a4f72c4  tcpfit.sh
8a521bcc2f89c336fba239d7b722cede8638ac9df06b28eb8be1536a22fd5085  install.sh

v0.4.5

Choose a tag to compare

@Kylin010 Kylin010 released this 09 Aug 17:41

升级

tcpfit update

改动

调优结尾的 swap 提示改成输入大小

原先是 y/n 固定建 2G, 现在可以指定:

  ▸ swap

    本机 961 MB 内存且没有 swap. 跑代理时 TCP 缓冲区可能撑爆内存,
    代理进程被系统杀掉.

    输入 1-20 的数字(单位 GB), 推荐 1-4;回车 = 2;输入 0 = 不创建.

  swap 大小 GB [2]:

非法输入会循环重问, 不再退出脚本

原先把输入直接丢给 harden, 非法值触发它的 die, 整个脚本跟着退出 —— 连 "调优完成" 都打不出来. 这正是 v0.4.3 上 "按 y 之后直接结束" 的成因.

现在 abc99 这类输入只会提示重输.

输入 结果
回车 建 2G
4 建 4G
2G 建 2G
0 跳过
abc / 99 提示重输

继承 v0.4.4

harden --swap 2G 被误判为非法参数的问题(v0.4.2 引入).

v0.4.4

Choose a tag to compare

@Kylin010 Kylin010 released this 09 Aug 17:36

升级

tcpfit update

修复

调优结尾的「创建 2G swap?」按 y 之后直接退出

小内存机(≤1G)且没有 swap 时, 一键调优结尾会问要不要加 swap. 按 y 之后脚本直接结束, swap 没被创建, 连 "调优完成" 都没打出来.

原因: v0.4.2 为了修「--swap 2M 会建成 2GB」把参数校验改成只收纯数字, 但向导和文档里写的都是 --swap 2G, 带单位的写法被一并挡掉, 触发 die 让整个脚本退出.

现在 22G 都收, 仍然拒绝 2M 这类会引发歧义的写法:

--swap 2G   ✓
--swap 2g   ✓
--swap 2    ✓
--swap 2M   ✗  拒绝(fallocate 建 2MB 而失败回退的 dd 建 2GB, 差 1000 倍)
--swap 0    ✗
--swap 21   ✗

顺带把参数校验挪到存快照之前 —— 打错参数不该留下状态文件.

受影响的还有

  • 脚本自带用法说明里的 tcpfit harden --swap 2G
  • 基础调优结尾给小内存机的建议 tcpfit harden --swap 2G

这两条在 v0.4.2 – v0.4.3 上直接执行也会失败.

v0.4.3

Choose a tag to compare

@Kylin010 Kylin010 released this 09 Aug 17:25

升级

tcpfit update

改动

手填测速对端时当场校验可达性

原先填错 IP 或端口要等到执行阶段才发现, 那时前面三个问题都白填了, 而且 sysctl 已经改过.

对端 IP / 域名(回车=公共节点): 192.0.2.99
    检查 192.0.2.99:5201 … 连不上
      常见原因: 对端没在跑 iperf3 -s / 端口填错 / 防火墙挡了 / IP 打错
      回车可以改用公共节点.

对端 IP / 域名(回车=公共节点): 10.0.0.5
    检查 10.0.0.5:5201 … 可达

连不上就当场重填, 也可以回车改用公共节点. 支持 IP:端口 写法.

继承 v0.4.0 – v0.4.2

  • sweep 失败时不再应用上一次的限速值
  • 细扫不再丢掉粗扫已找到的拐点
  • 扫描区间终点必测, 高丢包时上界按丢包率放宽
  • verify 的重传判定改用丢包率
  • 锁被占时列出持有者并可一键结束, 且只杀记录的 PID
  • Alpine / BusyBox 兼容