当前位置: 首页 > news >正文

IPv6 网络访问异常 | 时好时坏 / 部分访问正常

注:本文为 “ IPv6 间接性连接异常” 相关文章合辑

略作重排,未去重。

如有内容异常,请看原文。


IPv6 间接性连接异常?尝试调整路由器的 MTU 设置

Nero978
2024-1-29 17:54

背景

2024 年 1 月 29 日,因寒假返家,发现家中宽带已由父亲升级至 1000M。为获得更优的学习与娱乐体验,基于“买新不买旧”的原则,将家中老旧的 Wifi 5 路由器更换为最新的 Wifi 7 路由器(TP-Link BE5100,型号为 TL-7DR5130)。在设置新路由器时,看到 IPv6 的设置选项,便顺手将其开启。

img

然而,开启 IPv6 后出现了网络连接问题,无法正常上网。具体表现为:访问 baidu.com、fanyi.baidu.com 以及个人网站 www.rxgzs.cn、nero978.top 时,均显示连接超时(TIMED OUT)。

解决思路

由于个人网站支持 IPv6 访问,因此首先怀疑是路由器 IPv6 设置存在问题。为验证这一猜测,尝试访问一些 IPv4 网站,结果显示访问正常(可通过打开浏览器的 F12 键,进入开发者工具中的网络选项进行查看,返回状态码为 200 OK)。

通过上述测试,基本可以确定是 IPv6 方面的问题。随后查看了电脑本地的网络连接,确认已获取到 IPv6 地址,这表明从路由器到电脑的 IPv6 链路已成功建立。

接着,将路由器的 IPv6 设置关闭,再次尝试访问之前无法打开的网站,此时通过 IPv4 访问,网站均能正常打开(状态码为 200 OK)。至此,可以确定问题出在 IPv6 设置上。

针对 IPv6 出现的问题,访问了 test-ipv6.com 检测网站进行测试,测试得分为 10 分。

img

进一步分析发现,并非所有的 IPv6 网站都无法访问。例如,test-ipv6 网站本身就是基于 IPv6 的,且能够检测到本地的 IPv6 IP 地址,这说明本地的 IPv6 网络实际上是连通的。

由于部分 IPv6 网站无法访问,推测可能是 DNS 污染问题。于是更换为阿里的公共 DNS,但问题依然存在。

随后咨询了中国电信客服,得知截至当时,湖南电信已全面支持 IPv6。

在尝试了多种方法仍未解决问题后,浏览相关技术论坛(贴吧),从中获取了一些解决思路。

终极方案

经过在技术论坛上的研究,发现问题的根源在于 MTU(最大传输单元)设置。

将路由器的 MTU 设置为 1432 后,网络连接问题得到完美解决(TP 路由器的默认 MTU 为 1500)。

img

什么是 MTU ?

最大传输单元(Maximum Transmission Unit,MTU)是指在网络通信中,用于通知对方所能接受数据服务单元的最大尺寸,它规定了发送方能够发送的有效载荷的最大大小。MTU 表示的是数据包或帧的最大长度,通常以字节为单位。若 MTU 设置过大,数据包在经过路由器时可能会因超出其处理能力而被拒绝转发;若 MTU 设置过小,由于协议需要在数据包(或帧)上添加包头,实际传输的数据量会相应减少,从而降低传输效率。大多数操作系统会为用户提供一个默认的 MTU 值,该值一般能满足用户的常规需求。

为什么 IPv6 设置之后需要重新设置 MTU?

由于 IPv6 协议对 MTU 长度的要求与 IPv4 不同,在使用 IPv6 时,可能会出现某些网站偶尔无法访问的情况。其原因在于 MTU 设置过大,当数据包需要进行分包时,网络中一些不支持分包的设备会将这些数据包丢弃,导致网站无法访问。解决这一问题的方法是将路由器的 MTU 设置为较小的值(比 IPv4 的 MTU 小 20 字节,例如 1432 字节)。

什么是 PMTU 黑洞?

终端设备在发送数据包时,可以设置 DF(Don’t Fragment)标记,以告知路由器不要对数据包进行分片。当中间路由器接收到超过 MTU 的数据包时,会将其丢弃,并回复一条 ICMP Fragmentation Needed 消息。发送者收到该消息后,会在下次发送较小的数据包,这一过程称为 PMTU Discovery(路径最大传输单元发现)。在实际网络中,HTTPS(TLS)的流量大多带有 DF 标记。

然而,互联网上存在大量中间设备,由于安全考虑或配置不当,这些设备不会回应 ICMP Fragmentation Needed 包。这就导致在访问某些网站时,如果数据包的大小超过了 PMTU,数据包会被无声地丢弃,直到 TCP 协议检测到超时丢包并进行重传,这一过程会严重影响网络访问速度。当出现这种情况时,可以认为在本地与目标服务器之间的路径上存在 PMTU 黑洞。

由于本地到目标服务器之间的网络链路是动态变化的,在链路节点中,如果遇到配置错误的设备,就可能导致无法访问目标网站。

目前,国内 ISP(互联网服务提供商)一般通过 PPPoE 虚拟拨号建立 WAN 口连接。Ethernet 的默认 MTU 为 1500 字节,但 PPPoE 隧道会产生 8 个字节的开销,因此 PPPoE 虚连接的 MTU 为 (1500 - 8 = 1492) 字节。在 IPv4 协议下,减去 IPv4 包头(20 字节)和 TCP 包头(20 字节)后,可以得知需要将 MSS(最大段大小)设置为 1452 字节以下;在 IPv6 协议下,由于 IPv6 的包头为 40 字节,所以需要将 MSS 设置为 1432 字节以下。

由此可见,可能是家庭网络中的某台设备未能正确执行分包策略(即当数据包过大时,未发送要求分包的信息),导致 TCP 协议不断发送请求,最终出现连接超时(TIMED OUT)的情况。


使用 IPv6 后部分网站无法访问的问题解决方案

作者:neucrack
创建日期:2022 年 01 月 05 日

由于 IPv6 协议对 MTU 长度的要求与 IPv4 不同,在使用 IPv6 时,可能会出现某些网站偶尔无法访问的情况。其原因在于 MTU 设置过大,当数据包需要进行分包时,网络中一些不支持分包且不会响应请求设备分包需求的设备会将这些数据包丢弃,导致网站无法访问。解决这一问题的方法是将路由器的 MTU 设置为较小的值(比 IPv4 的 MTU 小 20 字节,例如 1432 字节)。

在公司网络支持 IPv6 后,访问一些网站时出现了无法访问或访问速度极慢的问题。经过 @vowstar 的排查,发现问题根源并成功解决。

相关解决方案如下:

之前在 IPv6 环境下,简书时而可以访问时而无法访问的根本原因已找到,是由于 PMTU 黑洞导致的,具体细节如下:

终端设备在发送数据包时,也可以设置 DF(Don’t Fragment)标记,以告知路由器不要对数据包进行分片。当中间路由器接收到超过 MTU 的数据包时,会将其丢弃,并回复一条 ICMP Fragmentation Needed 消息。发送者收到该消息后,会在下次发送较小的数据包,这一过程称为 PMTU Discovery(路径最大传输单元发现)。在实际网络中,HTTPS(TLS)的流量大多带有 DF 标记。
 
然而,互联网上存在大量中间设备,由于安全考虑或配置不当,这些设备不会回应 ICMP Fragmentation Needed 包。这就导致在访问某些网站时,如果数据包的大小超过了 PMTU,数据包会被无声地丢弃,直到 TCP 协议检测到超时丢包并进行重传,这一过程会严重影响网络访问速度。当出现这种情况时,可以认为在本地与目标服务器之间的路径上存在 PMTU 黑洞。
 
由于本地到简书之间的网络链路是动态变化的,在链路节点中,如果遇到配置错误的设备,就可能导致无法访问简书。

目前,国内 ISP(互联网服务提供商)一般通过 PPPoE 虚拟拨号建立 WAN 口连接。Ethernet 的默认 MTU 为 1500 字节,但 PPPoE 隧道会产生 8 个字节的开销,因此 PPPoE 虚连接的 MTU 为 (1500 - 8 = 1492) 字节。在 IPv4 协议下,减去 IPv4 包头(20 字节)和 TCP 包头(20 字节)后,可以得知需要将 MSS(最大段大小)设置为 1452 字节以下;在 IPv6 协议下,由于 IPv6 的包头为 40 字节,所以需要将 MSS 设置为 1432 字节以下。

解决方法:

#set security flow tcp-mss all-tcp mss 1452
#set security flow tcp-mss all-tcp mss 1432

将原先的设置值 1452 更改为 1432 后,强制丢包现象消失,原先无法访问的简书可以正常访问了。

路由器后台一般可以直接进行更改,在电脑的 Linux 系统中,可临时执行以下命令:

sudo ifconfig enp7s0 mtu 1432 up

从原理到实践,彻底解决 IPv6 上网不稳定的问题

作者:折腾总匠 _zhihu

发布于 2023 - 04 - 12 22:01・IP 属地广东

许多用户在开启 IPv6 后,遇到了网页加载缓慢、无法打开,视频卡顿,手机 App 运行不流畅等问题。本文将从原理层面深入分析这些问题,帮助读者理解问题产生的原因,并提供有效的解决方案。

前言

当前,私有云 NAS 在家中部署日益流行,但一般家庭或企业宽带通常没有公网 IP,在外访问 NAS 需通过 NAS 或第三方服务器进行中转,而这些中转服务提供的带宽往往较小,远不及公有云(如各种网盘)的带宽,严重限制了 NAS 的使用范围。

得益于国家对 IPv6 的大力推广,截至 2023 年,各大电信运营商已在局端默认向终端用户开通了公网 IPv6。然而,由于接入路由器的多样性和技术复杂性,运营商的安装维护人员通常未在拨号路由器上启用 IPv6,且对外宣称不支持公网 IPv6。许多技术爱好者自行登录光猫,将其更改为桥接模式,并使其支持 v4/v6 双协议,然后在自己的路由器上启用 IPv6,从而使 NAS 获得了公网 IPv6 地址,实现了在外全速访问 NAS。

但随之而来的是,家庭网络出现了变慢的情况,具体表现为部分网页加载缓慢或无法打开,视频卡顿甚至停止播放,手机 App 也存在类似问题。关闭路由器的 IPv6 功能后,网络恢复正常。咨询运营商的安装人员,得到的建议是关闭 IPv6,理由是目前 IPv6 技术尚不成熟。通过网络查找资料,发现许多文章讲解不全面,概念模糊,按照这些文章的方法操作后,问题仍未得到解决。

实际上,问题的根本原因在于 PMTU 分片缺陷。本文将从原理出发,深入分析这一问题,力求做到通俗易懂,帮助读者理解问题的本质,并提供有效的解决方案。阅读本文需要具备一定的网络知识,了解 TCP/IP/ 以太网分层模型及相关概念。

为什么 IPv4 没有这个问题?

有人认为 IPv6 技术不成熟,但这种观点是错误的。IPv6 已经推广运行多年,骨干网和城域网都已稳定运行,各大互联网公司也均支持 IPv6 访问,至少在普通互联网应用方面已相当成熟。我们的手机默认开启 IPv6,也并未出现明显的不稳定情况。如果说存在不成熟的地方,那主要是在网络的“最后一公里”,即家庭拨号路由器或接入的第三方宽带存在问题,可能是 IPv6 功能不完善或配置不正确,未能解决 PMTU 分片缺陷问题。

那么,为什么 IPv4 没有出现类似的问题呢?

  1. IPv4 支持分片功能,这使得大多数允许分片的互联网应用能够正常运行,尽管分片会导致一定的效率下降。
  2. 大多数家用路由器默认对 IPv4 开启了 MSS Clamping(最大段大小钳制)功能,但对 IPv6 却未默认开启。

因此,对于 IPv6 网络中出现的问题,可以尝试打开 MSS Clamping 功能来解决。

怎么判断 PMTU 分片缺陷问题?

如果网络在开启 IPv6 后出现上述问题,虽然有较大可能是 PMTU 分片缺陷导致的,但为了准确定位和诊断问题,还需要进行一些测试。

需要下载抓包工具 Wireshark,用于捕获电脑上网时的网络连接数据包。为了便于查看,只需捕获电脑访问服务器时 TCP 连接建立的瞬间数据包。首先,通过 ping 命令(如 ping 知乎网站 http://www.zhihu.com) ,在 IPv6 DNS 优先解析的情况下会得到 IPv6 地址)获取服务器的 IPv6 地址,然后在 Wireshark 的【捕获】【选项】中设置过滤器为 src host [你电脑 IP] || dst host [服务器 IP] ,开始捕获数据包。如果捕获到的 [SYN, ACK] 回包的 MSS 值比 [SYN] 去包小 8 字节,说明路由器已正确配置了 MSS Clamping;如果回包的 MSS 值与去包一致(均为 1440),则表明存在 PMTU 分片问题,需要进行相应的配置。

要深入理解这一问题,还需要了解 MSS Clamping、PMTU 分片缺陷、数据包分片以及 IPv6 不支持分片的原因等相关概念,这些都与 MTU 密切相关。

从 MTU 说起

最大传输单元 MTU(Maximum Transmission Unit)是指网络能够传输的最大数据包大小,以字节为单位。MTU 的大小决定了发送端一次能够发送报文的最大字节数。如果 MTU 超过了接收端或传输路径上设备的承受能力,会导致报文分片甚至丢弃,增加网络传输负担;如果 MTU 过小,则会降低实际传输的数据量,影响传输效率。

MTU 描述了数据链路层的收发能力,IP 层也需要依据 MTU 进行正确的分片逻辑,因此 MTU 是链路层和 IP 层之间的一种约定。它规定从网络层发到二层的数据(IP 头 + IP Payload)不能大于 MTU,否则会被丢弃,这就要求数据包在网络层进行分片,以符合 MTU 的大小要求。

MTU 对 IP 协议进行约束的原因在于二层网络信道的多样性,不同的二层网络所能传输的最大有效载荷不同。例如,常规以太网数据包的有效负载最长可达 1500 字节;增强版的以太网巨型帧可将最大帧长扩展到 9K;令牌环和 FDDI 能够传输更大的数据包,并且有时使用更大的数据包来减少高速或大容量数据传输的开销。

此外,隧道技术的应用也会影响 MTU 的大小。隧道技术是指网关设备将一种协议的数据包封装到另一个协议中,以便在网络中传输到另一个网关的过程。隧道技术本质上是一种数据包封装技术,在底层协议 MTU 不变的情况下,被封装的协议由于增加了额外的报文头部,其支持的数据净荷会相应减小。常见的隧道技术包括 xDSL 的 PPPoE、IPSec/L2TP 等 VPN、通用路由封装 (GRE) 协议等。

以 PPPoE 拨号为例,它在以太网帧中插入了 8 个字节的 PPP 头部,导致以太网的有效负载减少了 8 字节,为第三层仅保留了 1492 字节的传输空间。同样,通用路由封装 (GRE) 使用 24 字节头部,将 GRE 隧道上的 MTU 减少到 1476 字节。显然,多种封装技术的组合会进一步减小 MTU 的大小,如 ADSL 上运行的 GRE 隧道的 MTU 仅为 1468 字节。

在 Linux 系统中,可以使用 ifconfig 命令查看某个网络接口的 MTU 大小,示例如下:

# ifconfig
ppp0      Link encap:Point-to-Point Protocolinet addr:112.91.246.207  P-t-P:113.90.244.1  Mask:255.255.255.255UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1492  Metric:1RX packets:339211 errors:0 dropped:0 overruns:0 frame:0TX packets:352650 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:3RX bytes:165885364 (158.2 MiB)  TX bytes:78543988 (74.9 MiB)
eth2      Link encap:Ethernet  HWaddr 20:76:93:53:E0:93UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:2732205 errors:0 dropped:0 overruns:0 frame:0TX packets:2311855 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000RX bytes:2931869236 (2.7 GiB)  TX bytes:1896190225 (1.7 GiB)Interrupt:11

在 Windows 系统中,查看网络接口 MTU 的命令如下:

C:\> netsh interface ipv4 show subinterfacesMTU  MediaSenseState   传入字节  传出字节      接口
------  ---------------  ---------  ---------  -------------
4294967295                1          0    1039833  Loopback Pseudo-Interface 11500                2  116351254   52169177  WLAN1500                1   29136662    9016213  以太网

在 Windows 系统中设置 MTU 的命令(需以管理员身份运行命令提示符):

netsh interface ipv4 set subinterface "需修改的连接名" mtu = 值 store=persistent

例如,将 WLAN 连接的 MTU 设置为 1492,命令如下:

netsh interface ipv4 set subinterface "WLAN" mtu=1492 store=persistent

MTU 与 IP 分片

IPv4 的分片功能位于网络层,是网络层的重要特性。当源节点收到上层下发的 IP 包,或者中间路由器收到需要转发的 IP 包时,如果包大小大于设定的 MTU,就需要对该 IP 包进行分片,将其分成两个或多个 IP 包依次发送。每个分片所承载数据的首字节在原包中的索引会记录在包头的偏移字段中(以 8 字节为单位),并且只要不是最后一片,包头的 MF (More Fragment) 标记都会设为 1,以便目标端对这些分片进行正确重组。

一个已经分片的 IP 包,如果在传输过程中遇到 MTU 更小的节点,还会进行二次分片或多次分片,这会进一步降低通信效率,如下图所示:
img

以一个较为常见的两次分片场景为例,假设源端 PC 网卡的 MTU 为 1500,经过家用路由器拨号(MTU 为 1492)连接到城域网,最后经过某机房的路由器接入到服务器。由于该机房采用了某种隧道技术,机房路由器的 MTU 被设置为 1484。假设源端要发送一个 1500 字节的 IP 数据包,该数据包到达家用路由器后会被分片成 1492B 和 28B(IP 头部增加了 20B)两个 IP 包,1492B 的包到达机房路由器后会进一步分片为 1484B 和 28B 两个 IP 包,最后这三个 IP 包到达服务器后进行重组,解析出上层 TCP 报文。从数据效率来看,经过两次分片,多传输了 40 个字节。从网络资源消耗角度来看,一个包变成 3 个包,中间的每个路由器都需要分出计算资源进行解析、选路和转发,目标服务器端也需要进行重组,这些都是额外开销。如果源端发送一个大文件,被分段成 1 万个 1500B 的 IP 包,那么整个网络就要额外承载 2 万个小包。

有两种情况不允许分片:

  • 发送方应用程序设置了不允许分片(如 ICMP 的 PMTU 探测报文)。
  • IPv6 数据包不允许任何中间路径节点分片,只允许源节点分片。

正常情况下,IPv4 包大于 MTU 时会被分片。但有些上层报文(如 ICMP、TCP、UDP)为了保证数据的完整性,不希望在网络层因 MTU 的原因进行分片,它们宁愿丢弃数据包也不愿意分片后发送,比如下文将提及的 ICMP 的 PMTU 动态探测技术就是利用了这一特性。因此,IPv4 包头部的标志位除了 MF 外,还有一位是 DF (Don’t Fragment),如果发送端不希望报文被分片,可将 DF 设为 1,以阻止 IP 节点对 IP 包进行分片。下图为 IPv4 的包头格式:

img

IPv6 报文的基本头部没有分片标记和分片偏移字段,这些字段被移到了扩展头部,而中间路由器不会处理扩展头部(有 1 个例外),所以 IPv6 不允许任何中间节点对其进行分片。通过分段扩展首部,IPv6 允许源节点在发送时分片,经过中间节点的直接路由转发后,在目标节点对这些分片进行重组,这一过程与 IPv4 类似。下图描述了 IPv6 的包头相对 IPv4 的变化:

img

IPv6 被设计为不支持中间节点分片,主要原因有:

  1. 提升效率:在 IPv4 中,中间路由器的分片功能对路由器来说较为复杂且耗时,分成多片后显著增加了后续所有路由器的转发开销,对整个网络的通信效率产生了一定影响。IPv6 作为 IPv4 的升级协议,将分片功能移到源端和目标端进行,有效提升了中间路由器的转发效率。
  2. 提升安全性:分片一直是 IPv4 中安全漏洞的常见来源。对于分片的 IPv4 数据包,第 4 层报头信息(如 TCP)在第 2 个到最后一个分片中不可用。分片和分片重组的过程可能会在中间节点(如防火墙和路由器)和终端节点(如用户计算机)中产生意外和有害的行为。

PMTU (Path MTU) 及动态探测

Path MTU 即传输路径的 MTU,指无需分片就能穿过某路径的数据包最大长度。在从发送端到接收端的传输路径上,如果网元的 MTU 设置不一致,那么决定该路径可用 MTU 的是整条路径上的最小 MTU 值。以 Path MTU 作为 IP 包长发送数据,既能保证高效传输,又能避免分片,如下图所示:
img

PMTU 是一个动态概念,互联网上两台主机之间的 PMTU 并非固定值,它取决于当时所选择的路径,而且路由选择不一定是对称的(从 A 到 B 的路由可能与从 B 到 A 的路由不同),因此,PMTU 在两个方向上不一定一致。

RFC 1191 (IPv4) 和 RFC 1981 (IPv6) 定义了动态探测 PMTU 的技术 —— PMTUD (Path MTU Discovery),用于确定两个 IP 主机之间的 Path MTU。首先,源节点假设 Path MTU 就是其出接口的 MTU,发出一个试探性的报文,并设置该报文不允许被分片。当转发路径上存在一个小于当前假设的 Path MTU 时,转发设备就会向源节点发送回应的 ICMP 报文,并且携带自己的 MTU 值,此后源节点将 Path MTU 的假设值更改为新收到的 MTU 值继续发送报文。如此反复,直到报文到达目的地之后,源节点就能知道到达目的地的 Path MTU 了。
img

目前 IPv4 网络在发现 PMTU 方面存在困难,主要原因是:

  • 某些运营商或网站出于网络安全或其他考虑,过滤掉了 ICMP 探测报文。
  • Path MTU 需要主机和互联网上的各种网络设备(交换机、路由器、防火墙等)的配合,但有些网络设备不遵从 RFC 1191 协议。

IPv6 由于不支持中间路由节点分片,PMTU 发现机制就显得至关重要。如果源节点不执行 PMTU 发现,它必须发送不大于 1280 字节的最小 IPv6 MTU 大小的数据包。如果【数据包过大】的 ICMPv6 回传报文被某一路由器过滤掉,源节点将无法获知数据包被丢,这对于 IPv6 网络通信来说是极为严重的问题。

ping 程序的 ICMP 不可到达错误,采用的就是 PMTU 动态探测的方法,traceroute 程序也是利用这种方法来确定到达目的节点的 PMT。

我们可以使用 ping -f -l [SIZE] [目标 IP 或域名] 命令来探测到指定目的节点的 PMTU,其中 -f 表示强制不分片,-l 用于指定 ping 数据包的大小,最大能正常 ping 通的 SIZE 加上 ICMP 包头的 28 字节即为 MTU,示例如下:

C:\> ping -f -l 1465 www.baidu.com
正在 Ping www.a.shifen.com [14.119.104.254] 具有 1465 字节的数据:
需要拆分数据包但是设置 DF。
……
C:\> ping -f -l 1464 www.baidu.com
正在 Ping www.a.shifen.com [14.119.104.254] 具有 1464 字节的数据:
来自 14.119.104.254 的回复:字节 = 1464 时间 = 7ms TTL=56

实际环境下捕获的 ICMP 需要分片但 DF 位置一的差错报文,其解码格式如下图所示:
img

我们可以看到其差错类型为 3,代码为 4,并且告知了下一跳的 MTU 值为 1478。在 ICMP 差错报文里封装了导致此差错的原始 IP 报文的报头(包含 IP 报头和四层报头)。

PMTU 黑洞

在整个互联网网络中,虽然上层运行的都是 TCP/IP 协议,但由于底层通信媒介的多样性(以太网、无线、PPPoE 等)以及核心路由器和各级接入路由器配置的差异(即每个网元的链路层收发能力(MTU)不同),同时客户端 PC 到服务器之间的路由选路每次都可能不同,数据包的去程和回程路径也可能不同(非对称),因此每次路由的 PMTU 也不尽相同。

如果源发送端的 MTU 设置过大,而某次路由路径中的某个中间节点的 MTU 过小,且数据包被应用层设置了不允许分片,或者这是一个 IPv6 数据包,那么这个节点只能将该包丢弃,同时产生一条【数据包过大】的 ICMP 报文,告知源端自己能处理的 MTU。

不幸的是,这个 ICMP 报文不一定能回传到源端,因为回程的某个中间节点可能因安全原因禁用了 ICMP,将其丢弃。最终结果是,源发送端的上层不知道数据被丢,只能通过超时重传来尝试解决。然而,发送端判断超时的时间通常较长,在一个报文未发送完成的情况下,后续的所有报文都需要等待。更糟糕的是,发送端即使超时重传,重传的数据包仍有可能走同一条路径,同样被那个节点丢弃,最终导致上层业务阻塞,网页或视频一直处于加载状态。只有当路由选路避开那个节点时(这取决于网络的动态变化和运气),网络才能恢复正常。

这个导致数据包被丢弃且 ICMP 报文无法回传的节点就如同黑洞一般,隐藏在网络深处,悄无声息地吞噬大数据包,对上层通信业务造成严重影响。由于所有的 IPv6 数据包都不允许路由器分片,而 IPv4 只有部分应用不允许分片,因此 PMTU 黑洞对 IPv6 网络的影响尤为明显。

如何正确配置 MTU

MTU 的配置既不能过大,否则会造成分片,影响传输效率,甚至可能形成 PMTU 黑洞;也不能过小,过小会降低通信效率。需要根据不同场景和设备(源端、接入网络、骨干网、城域网络),配置一个合适的值。

需要特别注意的是,MTU 大小的选择与 IPv6 无关,因为 MTU 是数据链路层(二层)对上层的约束,无论第三层使用的是 IPv4 还是 IPv6,都需要遵守相同的 MTU 规定。不能因为上层使用 IPv6,其包头比 IPv4 大 20 字节,就认为 MTU 要相应减小。至于后面提到的防火墙的 –clamp-mss-to-pmtu 选项,那是 iptables 把 MSS 修改为 MTU,属于强行关联到 MTU,概念不可混淆。

MTU 大小选择的一个最基本的原则是,对接的两个三层设备以太网接口 MTU 配置需要保持一致。同时还需要考虑多种场景下各种封装标签对报文大小的影响,例如封装 MPLS 标签,每层标签会增加 4 字节,增加 MPLS 标签后,报文长度也可能超过链路层允许发送的范围,导致报文无法转发。
img

骨干 / 城域 / 接入网络 MTU 的配置

作为普通用户,可以信任骨干网、城域网和国内三大运营商提供的接入网络,其配置的路由设备通常较为可靠,由专业工程师进行配置,最低能保证最小 1500 的 MTU 设置。

为确保骨干网络、城域网络、接入网络的高效运行,MTU 通常被设置为远大于以太网标准的基本要求 1500 字节。现有的大型路由器、交换机设备一般都支持 9000 以上的大数据报文,但各厂商设备的缺省配置不尽相同,很多厂商设备的缺省 MTU 配置仍然是 1500 字节。并且由于网络中可能运行 OSPF、ISIS 等需要协商 MTU 的路由协议,因此互相对接的不同厂商设备的 MTU 也需要调整为相同。所以,在满足网络和运营商规范且各个厂商都支持的情况下,应尽量将 MTU 配置得大一些。

不过,一些小型接入网络服务提供商或个人提供的接入服务,由于技术水平参差不齐,其配置的 MTU 有可能小于 1500 字节。

数据中心 / 机房等服务器网络 MTU 的配置

作为服务器端的运维工程师,也需要关注 MTU 的配置。在数据中心等网络建设中,需要确定 MTU 的配置规范,在各个厂商都支持的情况下,尽量将 MTU 配置得大一些。

在目前大规模建设的数据中心等网络中,通常没有对 MTU 进行统一调整。随着新技术的应用,MTU 的问题会逐渐暴露出来。例如,为实现大二层扩展而采用的各类隧道技术(如 VPLS、VXLAN 等),这些技术都会使用额外的封装,形成超大报文,例如 VXLAN 会在原始报文基础上增加 50 字节。如果不统一规划 MTU,会导致传输效率低下,甚至业务中断。

家庭 / 企业终端网络 MTU 的配置

对于普通家庭或企业网络这些终端网络的配置,路由器的配置要与接入网端设备相对应。例如,国内常用的 PPPoE 拨号接入,路由器 MTU 配置为 1492 ,比以太网少 8 字节即可。

如果局域网上的 PC 主要用于访问公网,那么将这些 PC 的 MTU 设置为与拨号路由器一致,能够避免拨号路由器进行 IP 分片。因为 PC 默认的 MTU 为 1500,比 PPPoE 多 8 字节。

在以下情况下,可以设置更小的 MTU 以提升通信效率,否则尽量保持默认或最大:

  1. 通过 ping -f -l 14xx [IP] 确定了到某一服务器的 PMTU 为更小值。
  2. 使用了 L2TP、IPSec 等 VPN 隧道,需要减去新增字段的大小。

为什么 IPv6 路由器不能随意减小 MTU

网上有些文章认为,由于 IPv6 包头多 20 字节,就要在路由器上设置更小的 MTU(比如 1432/1452/1472),但这种做法并不能解决问题。

我们知道,MTU 是第二层数据链路层定义的规范,表征的是数据链路层的数据收发能力,是对第三层的约束,与第三层使用的协议无关。单纯在路由器上减小 MTU 无法解决 IPv6 访问不稳定的问题(除非防火墙还开启了 MSS 钳制为 PMTU,这一点将在下文阐述),反而可能使问题恶化。例如,若将拨号路由器的 MTU 设置为 1432,而 PC 仍使用默认的 1500,那么大数据包到达路由器时就会被丢弃,因为 IPv6 不支持中间路由器分片。

当然,如果在源端 PC 上减小 MTU 到合适大小,是能够解决问题的。因为数据包在源端就被分成小片,中间路由器无需进行分片操作。

MSS 与 TCP 报文分段

MSS(Maximum Segment Size,最大报文长度)是指 TCP 提交给 IP 层的最大数据段大小,不包含 TCP Header 和 TCP Option,仅指 TCP Payload 的字节数。因此,MSS 是 TCP 用来限制应用层最大发送字节数的参数。

在 TCP 连接建立时,收发双方会协商后续通信时使用的 MSS(附在 SYN/ACK 报文头部的可选字段中),指示每一个报文段所能承载的最大数据长度。

在以太网环境下,MSS = MTU - 20 字节 TCP 报头 - 20 字节 IP 报头,若使用 PPPoE 还需再减去 8 字节帧头。MSS 值只会出现在 SYN 报文中,即当 SYN = 1 时,才会有 MSS 字段值。

PC 访问某网站时进行 TCP 三次握手的流程如下图所示:
img

  1. 首先客户端会发送一个 SYN 请求报文,该 SYN 报文的 “选项” 字段中会有 MSS 值(MSS = MTU - IP 首部长度 - TCP 首部长度)。此 MSS 值用于告知对方自己能够接受的最大发送数据大小。
  2. 当服务器端收到 SYN 报文后,会向请求端返回 SYN + ACK(同步确认报文),其中的 “选项” 字段同样会有 MSS 值。
  3. 通信双方选择 SYN 和 SYN + ACK 报文中较小的 MSS 作为此次 TCP 连接的 MSS,从而实现通信双方对 MSS 的协商。

双方在后续通信时,如果上层(应用层)下发的数据过长,超过 MSS,将按 MSS 的长度进行 TCP 报文的分段,分段后的报文再提交给 IP 层。由于 MSS 仅仅是源端和目标端双方协商的结果(还处于第四层),它们并不清楚中间节点的 PMTU,所以 MSS 只是描述了通信双方在 TCP 层的收发能力。源端和目标端之间的所有中间路由节点,对这个上层协商的 MSS 并不知晓。因此,在源端按 MSS 进行 TCP 报文分段后,如果 IP 报文长度超过 MTU,IP 层协议仍然会对其进行分片。可见,分段和分片是相互独立的过程。

由此可知,MSS 并不能从根本上解决 PMTU 黑洞问题,也无法解决因底层(IP)分片造成的传输效率问题。

MTU 和 MSS 的联系与区别

MTU 和 MSS 的相同点在于,它们均用于约束或协商通信双方的最大数据包长度。虽然 MSS 和 MTU 没有必然的直接联系,但是,对于通信发起方的源站点来说,为了在本机达到最高效率,MSS 应设置为本机 MTU - IP - Header (20) - TCP - Header (20) ,这样可以在最大长度的情况下,避免同一 TCP 报文被分成多个 IP 包 —— 但这仅适用于本机,中间路由节点仍会根据自身的 MTU 进行分片操作。

在以太网中,本机 MTU 与 MSS 的最佳关系如下图所示:
img

MTU 和 MSS 的主要区别如下:

  1. 协议层次不同:MTU 表征 OSI 模型的第二层数据链路层的通信能力,而 MSS 表征第四层传输层 TCP 的通信能力。
  2. 实现方式不同:MTU 仅仅是一个规范,是第二层对第三层的约束;而 MSS 不仅包含约束,还定义了 TCP 连接建立时关于收发能力的协商过程。
  3. 影响范围不同:MSS 仅影响源端和目标端,而 MTU 影响整个路由路径上的所有节点。

绝招:MSS Clamping

由上文可知,设置一个理想的 PMTU 几乎是不可能的,因为每次路由路径都可能不同,难以确定一个固定的理想值。我们最多只能根据经验设置一个相对合适的值,以降低分片或丢失的概率。MSS 仅用于通信双方的协商,中间节点对此并不了解,无法解决本质问题。虽然 PMTUD(PMTU 探测)机制有望解决这个问题,但由于网络上大量节点关闭了 ICMP,导致该机制难以发挥作用。

MSS 的最大优势在于,它具有连接建立时的协商机制,能够约束源端高层(TCP)发送数据段的大小。然而,其协商出的值不准确,不能反映整个路由路径的传输能力,从而限制了其效能。假如这个数值能够由整个路由路径上的每一个节点参与协商,那么得出的 MSS 值将与 PMTU 一样准确。此时,源端高层按照这个数值进行 TCP 分段,那么源端发出的每一个 IP 包的大小都将恰到好处,只要路由路径不变,这些 IP 包都将被正确转发且无需分片。这是一种非常完美的机制!

MSS Clamping(MSS 钳制)就是这样一种打破层级界限的解决方案。它运行在路由器上,对经过的每一个包(无论是转发的包还是上层提交的包)进行嗅探。如果发现某一包是 TCP 连接建立的握手包,就会查看其中正在协商的 MSS 值(SYN/ACK 包中的 MSS 字段)。一旦发现该值比本机的 MTU 换算出来的 MSS 值大,就会修改包中的 MSS,将其调整为本机换算的 MSS 值(即:本机 MTU - IP 头 - TCP 头)。而通信双方并不知晓这一操作,它们仍以为包中的 MSS 值就是对方的 MSS,并将本次连接的 MSS 修改为这个更小的值。如果经过的所有路由器都开启了 MSS 钳制,那么到达源端/终端的 SYN/ACK 包中的 MSS 值就一定是整个路由路径中所有节点最小的 PMTU,这是一种非常完美的机制!

下图详细解释了 MSS Clamping 的整个流程,以及后续的数据收发细节:
img

从通信协议设计的角度来看,MSS Clamping 打破了传统的分层设计。整个 TCP/IP 协议栈采用分层设计,而它工作在第三层,却强行修改第四层的数据包。并且,MSS 协商机制原本仅用于通信双方交流收发能力,而它却允许中间节点查看甚至篡改协商内容。但从更高的层面来看,这种打破层级思维界限、敢于推翻旧秩序、建立新秩序的方式,在解决网络问题上具有重要意义。

看到这里,可能会产生一个疑问:TCP 连接建立后,路由路径不可能一直保持不变,那么连接建立时钳制出来的 MSS,在后续是否还准确?从理论上讲,确实存在不准确的情况。但在实际应用中,骨干/城域/接入网络通常能够保障 MTU ≥ 1500,互联网服务商的路由设备也由专业网管人员维护,一般也能达到这一标准。问题更多地出现在用户端的内部设备和拨号出口路由上,这些网络设备大多为中低端产品,其 MTU 往往是整条链路中最小的(如 PPPoE 的 1492)。此外,这些设备的功能是否完善、技术人员的专业水平如何,都存在不确定性。因此,PMTU 黑洞问题并非难以解决,关键在于解决网络的“最后一公里”问题。

我们再回过头来看整个路由路径,虽然骨干网、城域网和运营商的接入网可能会改变路径,但这些网络通常具有较高的稳定性和技术保障(MTU ≥ 1500)。而用户端路径和服务器端 IDC 机房路径相对固定,且技术保障相对较弱。因此,MSS Clamping 方案是解决 PMTU 分片和 IPv6 黑洞问题最为有效的方案。

还有一个问题,如何保证 TCP 通信途经的所有路由器都开启了 MSS Clamping 呢?实际上,我们并不需要所有路由器都开启该功能。根据木桶理论,最短的木板往往在技术保障最弱的用户端设备(也是路由选路的必经之路)。只要在这些设备的接入路由器上正确配置了 MSS Clamping,就能保证所钳制的 MSS 是全路径最小的。

哪些设备需要开启 MSS Clamping

从上文可知,骨干网、城域网、运营商的接入网络和 IDC 机房的内部网络,其二层大多运行以太网,能够保证 ≥ 1500 的有效负载。即使这些网络使用了不同的二层网络或复杂的隧道技术,由于有专业技术人员支持,即便无法达到 1500 的 MTU,也会正确配置 MSS Clamping。作为普通用户,无需过于关注这些网络。我们只需关注自己这边的通信设施。

引起 PMTU 变化的关键节点是那些连接不同网络进行转换的网关路由器,包括使用了隧道封装技术的各种网关(如 IPSec、L2TP 等 VPN、IPv6 - over - IPv4 或 IPv4 - over - IPv6 等)。我们需要特别关注这些设备,为其配置正确的 MSS Clamping。

例如,典型的 PPPoE 拨号路由器,它一端连接 MTU = 1500 的内网以太网,另一端连接 MTU = 1492 的 PPPoE 链路。如果没有正确配置 MSS,未开启 MSS Clamping,那么内网 PC 上发出的 IPv6 数据包很可能会被它丢弃。

正确设置 MSS Clamping

专业的路由器一般都支持 MSS Clamping。例如,Cisco 路由器的配置命令为 ip tcp adjust - mss [size],需要注意的是,该命令是双向的,会在所配置接口的入站和出站的 SYN / ACK 数据包中都进行钳制。

家用路由器如果采用拨号上网,厂商为了保证网络稳定,一般会默认开启 MSS Clamping。例如,基于华硕系统修改的 Padavan ,执行命令 iptables - L 可以看到这样一条转发规则:

[XXX - Router / home / root]# iptables - L
...
Chain FORWARD (policy DROP)
...
TCPMSS   tcp  --  anywhere      anywhere      tcp flags:SYN,RST/SYN TCPMSS clamp to PMTU

Linux 的 iptables / ip6tables 也支持 MSS Clamping,可以通过创建基于 mangle 表的 forward 链,并使用 --set - mss [size]--clamp - mss - to - pmtu 选项的规则来启用 MSS 钳制。既可以指定具体的 MSS 值,也可以直接钳制到 PMTU(实际上就是本机的 MTU)。例如:

# 下面命令钳制到 1452,适合 PPPoE 用户
iptables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --set - mss 1452
ip6tables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --set - mss 1452# 下面命令是自动钳制到 PMTU,此时应设置本机正确的 MTU,如 PPPoE 为 1492
iptables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --clamp - mss - to - pmtu
ip6tables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --clamp - mss - to - pmtu

如果要指定只对某一网络接口进行钳制,而不是对所有转发的包都钳制,可以操作 PREROUTING 表,并指定拨号的接口名称(ppp0)。例如:

ip6tables - t mangle - A POSTROUTING - p tcp --tcp - flags SYN,RST SYN - o ppp0 - j TCPMSS --clamp - mss - to - pmtu

需要注意的是,IPv4 和 IPv6 要分别进行配置。其他基于 iptables 的路由器(如 Padavan)都可以参考这种方法。

在 OpenWrt 路由器上,除了通过修改 iptables 规则的方法,还可以通过 Luci 界面进行配置:在【网络】【防火墙】【基本设置】【区域】处,在对应接口上勾选【MSS 钳制】即可。

RouterOS 路由器设置 MSS Clamping 的命令如下(其中 pppoe - out1 是 wan 口,1432 是要设置的 MSS 值,请根据实际需求修改):

/ ipv6 firewall mangle add chain = forward out - interface = pppoe - out1 protocol = tcp tcp - flags = syn action = change - mss new - mss = 1432

UBNT Edgerouter 系列设备设置 MSS Clamping 的命令如下:

set firewall options mss - clamp6 interface - type pppoe
set firewall options mss - clamp6 mss 1432

其他中低端的路由器,配置界面上可能无法直接看到相关设置信息。但一般来说,IPv4 通常默认开启了 MSS Clamping,而 IPv6 则不一定。

蜂窝 4G 网络的 MSS 分析

我们知道,手机的数据网络早已采用 IPv6,并且默认优先使用 IPv6,但其上网一直稳定流畅。那么,移动运营商的 4G 网关是如何处理 IPv6 碎片问题的呢?为了探究这个问题,使用电信手机(MIUI 系统、4G 数据)开启热点,电脑(Windows 10)连接该热点,并使用 Wireshark 进行抓包分析。

这是 4G 网络下访问知乎 IPv6 服务器的截图:
img

这是 4G 网络下访问百度 IPv4 服务器的截图:
img

此时,Windows 电脑上 WLAN 连接的 MTU 被改为 1410:

C:\> netsh interface ipv6 show subinterfacesMTU  MediaSenseState   传入字节  传出字节      接口
------  ---------------  ---------  ---------  -------------1410                1  117539374   58911024  WLAN1500                5          0        152  本地连接 * 1

作为对比,这是同一台电脑连接 PPPoE 拨号路由器的 WIFI 后,访问知乎 IPv6 服务器的截图:
img

这是宽带 PPPoE 拨号访问百度 IPv4 服务器的截图:
img

此时,Windows 电脑上 WLAN 连接的 MTU 恢复为正常的 1500:

C:\> netsh interface ipv6 show subinterfacesMTU  MediaSenseState   传入字节  传出字节      接口
------  ---------------  ---------  ---------  -------------1500                1  118029364   62131090  WLAN1500                5          0        152  本地连接 * 1

通过分析可以发现,安卓系统 AP 程序或运营商的 4G 网关将 IPv6 的 MSS 调整为 1300,将 IPv4 的 MSS 调整为 1370,均比 PPPoE 拨号网络的 MSS 小很多。

这里存在几个尚未明确的问题:

  1. 电脑连接手机热点后,其 MTU 被调整为 1410,比正常的 1500 少了 90 字节。手机热点是如何更改电脑 MTU 的呢?是否通过 DHCP 实现?
  2. 安卓系统 AP 程序或运营商的 4G 网关为何采用更小的 MSS?是蜂窝网络自身的 MTU 更小,还是 4G 接入网络采用了其他隧道技术,亦或是特意调小以增强 IPv6 的适应性?综合其他网友的实验,不同品牌手机的 MTU 各不相同,有的为 1432,而 iPhone 的 MTU 仅 1280。由此推测,更大的可能性是手机为提升 IPv6 的适应性,特意将 MSS 调小。

不管怎样,如果在拨号路由器开启 MSS Clamping 的情况下,将 MTU 设为 1492 仍无法保证网络稳定,可考虑借鉴 4G 网络的设置,将 IPv6 的 MSS 也调整为 1300,或把 MTU 设置为 1368。

双栈 DNS 优化

在双栈环境下,究竟使用哪个协议栈?是否有优先顺序可供设置?是由客户应用程序、底层操作系统,还是 DNS 服务器决定优先采用哪个协议栈呢?

答案是由应用程序自行决策。标准的 DNS 服务器无法控制程序优先使用哪个协议,它只能同时提供 IPv4 和 IPv6 的域名记录供客户端查询。客户端应用程序在建立 TCP 连接前,首先要将域名转换为 IP 地址,这通过向域名服务器发起 DNS 查询请求来实现。在 DNS 请求时,需要指定查询类型,IPv4 地址对应的查询类型为 A,IPv6 地址对应的查询类型为 AAAA。应用程序既可以只查询其中一种地址,也可以同时查询两种地址,然后依据自身逻辑选择使用哪个地址。对于绝大多数使用 BSD socket API 的应用程序,会通过 getaddrinfo 函数来解析域名,然后依次尝试连接,此时优先使用哪种协议由底层系统控制,getaddrinfo 函数将哪种协议排在前面,程序就会优先连接该协议。还有一些经过特殊设计的程序,比如 curl 以及各种浏览器,则具有其他逻辑。例如,它们会先检查本机的 IPv6 地址,如果是内网地址则会放弃使用 IPv6;如果是公网地址,会同时解析 IPv4 和 IPv6 地址,然后优先连接 IPv6,如果在较短时间内(如 1 秒)未能连接成功,则会继续尝试连接 IPv4,最终使用最早建立的连接。【本段内容摘自 Richard Yu 的评论,特此感谢】

目前,大多数终端设备(包括 PC 和手机)的知名应用程序(如浏览器)和操作系统默认都支持 IPv6,能够同时运行 v4/v6 双栈网络。如果路由器开启了 IPv6 DHCP,终端设备就能自动获取运营商提供的 IPv6 DNS 服务器地址。该 DNS 服务器不仅包含传统的 IPv4 记录,还拥有 IPv6 记录。而应用程序(通过 getaddrinfo 函数)通常会优先查询到 IPv6 地址,并使用该地址建立 TCP 连接,数据自然会通过 IPv6 协议栈传输。

例如,当我们访问知乎时,由于知乎服务器开启了双栈支持,在 IPv6 DNS 上,域名 www.zhihu.com 同时指向了知乎的 IPv6 和 IPv4 服务器地址。因此,浏览器在解析域名时会同时获取这两个地址,并且通常会优先使用 IPv6 地址建立连接,后续的 Web 流量也就通过 IPv6 协议栈传输。

这种 IPv6 优先的策略本身并无问题,但在当前的互联网环境中,多数互联网服务(网站)的 IPv4 网络性能优于 IPv6,少数互联网服务则可能出现 IPv6 网络性能优于 IPv4 的情况。如果存在这样一种 DNS 服务器,我们可以自行指定其优先返回 IPv4 地址或 IPv6 地址,甚至更智能地,它能从多个 IPv4 和 IPv6 地址中筛选出访问速度最快的 IP 地址返回给客户端。

SmartDNS 就是这样一款神器,它是一个运行在本地的 DNS 服务器,能够接收本地客户端的 DNS 查询请求,然后从多个上游 DNS 服务器获取 DNS 查询结果,并将访问速度最快的结果返回给客户端,从而提高网络访问速度。

SmartDNS 的架构和运行原理如下:

  1. SmartDNS 接收本地网络设备(如 PC、手机)的 DNS 查询请求。
  2. 将查询请求发送到多个上游 DNS 服务器,支持 UDP 标准端口或非标准端口查询,以及 TCP 查询。
  3. 上游 DNS 服务器返回域名对应的服务器 IP 地址列表,SmartDNS 则检测从本地网络访问这些服务器 IP 的速度。
  4. 最后将访问速度最快的服务器 IP 返回给本地客户端。

img

借助 SmartDNS,我们可以在本地搭建自己的智能 DNS 服务器,以优化网络。例如,可以将其以插件形式安装在 OpenWRT 路由器上,具体安装过程在此不再赘述。

总结

综上所述,开启 IPv6 后网络出现的不稳定问题,很大程度上可能是由 PMTU 黑洞导致的。解决这一问题的关键在于在拨号路由器上开启 MSS Clamping 功能,在传输层将数据分段为最合适的大小,避免中间路由器进行 IP 分片操作。

本文参考文章:

  1. 华为 IP 百科 什么是 MTU

  2. 小菜学编程 IP 分片

  3. 大西洋里的鱼 MTU TCP-MSS 详解

  4. CISCO PPPoE 连接的以太网 MTU 和 TCP MSS 调整概念

  5. raysonx 开启 IPv6 后网速变得很慢?可能是 PMTU 黑洞的问题

  6. SmartDNS SmartDNS (pymumu.github.io)


via:

  • IPv6 间接性抽风?试试路由器的 MTU 设置。 – Nero978 的日记
    https://nero978.top/archives/204

  • 使用 IPv6 后一些网站无法访问,有时能访问有时无法访问问题解决 - 次世代 BUG 池
    https://neucrack.com/p/400

  • 从原理到实践,彻底告别 IPv6 上网不稳定的问题 - 知乎
    https://zhuanlan.zhihu.com/p/621371177

相关文章:

IPv6 网络访问异常 | 时好时坏 / 部分访问正常

注:本文为 “ IPv6 间接性连接异常” 相关文章合辑。 略作重排,未去重。 如有内容异常,请看原文。 IPv6 间接性连接异常?尝试调整路由器的 MTU 设置 Nero978 2024-1-29 17:54 背景 2024 年 1 月 29 日,因寒假返家…...

Unity编辑器功能及拓展(1) —特殊的Editor文件夹

Unity中的Editor文件夹是一个具有特殊用途的目录,主要用于存放与编辑器扩展功能相关的脚本和资源。 一.纠缠不清的UnityEditor 我们Unity中进行游戏构建时,我们经常遇到关于UnityEditor相关命名空间丢失的报错,这时候,只得将报错…...

LLMs之PE:《Tracing the thoughts of a large language model》翻译与解读

LLMs之PE:《Tracing the thoughts of a large language model》翻译与解读 导读:这篇论文的核心贡献在于提出了一种新颖的、基于提示工程的LLMs推理过程追踪技术——“Tracing Thoughts”。该技术通过精心设计的提示,引导LLMs生成其推理过程的…...

[Python] 贪心算法简单版

贪心算法-简单版 贪心算法的一般使用场景是给定一个列表ls, 让你在使用最少的数据的情况下达到或超过n. 我们就来使用上面讲到的这个朴素的例题来讲讲贪心算法的基本模板: 2-1.排序 既然要用最少的数据, 我们就要优先用大的数据拼, 为了实现这个效果, 我们得先给列表从大到小…...

游戏引擎学习第191天

回顾并制定今天的计划 最近几天,我们有一些偏离了原计划的方向,主要是开始了一些调试代码的工作。最初我们计划进行一些调试功能的添加,但是随着工作的深入,我们开始清理和整理调试界面的呈现方式,以便能够做一些更复…...

Git撤回操作全场景指南:未推送与已推送,保留和不保留修改的差异处理

一、未推送到远程仓库的提交(仅本地存在) 特点:可直接修改本地提交历史,不会影响他人 1. 保留修改重新提交 git reset --soft HEAD~1 # 操作效果: # - 撤销最后一次提交 # - 保留工作区所有修改 # - 暂存区内容保持…...

Java 贪吃蛇游戏

这段 Java 代码实现了一个经典的贪吃蛇游戏。玩家可以使用键盘的上下左右箭头键控制蛇的移动方向,蛇会在游戏面板中移动并尝试吃掉随机生成的食物。每吃掉一个食物,蛇的身体会变长,玩家的得分也会增加。如果蛇撞到自己的身体或者撞到游戏面板…...

QT图片轮播器(QT实操学习2)

1.项目架构 1.UI界面 2.widget.h​ #ifndef WIDGET_H #define WIDGET_H#include <QWidget>#define TIMEOUT 1 * 1000 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent n…...

mac m1/m2/m3 pyaudio的安装

google了很多方法&#xff0c;也尝试了 issue68的方法&#xff0c; 但是均失败了&#xff0c;但是问deepseek竟然成功了&#xff0c;下面是deepseek r1给出的方法。在M3 pro芯片上可以成功运行. 安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent…...

Appium中元素定位的注意点

应用场景 了解这些注意点可以以后在出错误的时候&#xff0c;更快速的定位问题原因。 示例 使用 find_element_by_xx 或 find_elements_by_xx 的方法&#xff0c;分别传入一个没有的“特征“会是什么结果呢? 核心代码 driver.find_element_by_id("xxx") drive…...

《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》

《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》 引言:从零到分析高手 数据是当代社会最宝贵的资源,而数据分析技能是现代职业人不可或缺的一部分。在数据科学的领域中,Python 已成为当之无愧的“首选语言”,其强大的生态系统和简洁的语法让人如虎添…...

[GWCTF 2019]我有一个数据库1 [CVE phpMyAdmin漏洞]

扫出来一些东西 访问/phpmyadmin 发现界面 这里用到了CVE-2018-12613&#xff0c;光速学习 出现漏洞的代码是&#xff1a; $target_blacklist array (import.php, export.php );// If we have a valid target, lets load that script instead if (! empty($_REQUEST[targe…...

spring 常用注解区别及使用场景

1. 组件注册注解 Bean 作用&#xff1a;用于方法上&#xff0c;表示该方法返回的对象由Spring容器管理。通常用于配置类&#xff08;Configuration&#xff09;中&#xff0c;注册第三方库或自定义的Bean。 使用场合&#xff1a; 当你需要将非Spring管理的类&#xff08;如第…...

【后端】【Django】信号使用详解

Django post_save 信号使用详解&#xff08;循序渐进&#xff09; 一、信号的基本概念 Django 的 信号&#xff08;Signal&#xff09; 允许不同部分的代码在发生某些事件时进行通信&#xff0c;而不需要直接调用。这种机制可以解耦代码&#xff0c;让不同的模块独立工作。 …...

ML算法数学概念

交叉熵损失&#xff08;Cross-Entropy Loss&#xff09; 是机器学习和深度学习中常用的一种损失函数&#xff0c;主要用于衡量两个概率分布之间的差异。它在分类问题中&#xff08;尤其是多分类问题&#xff09;被广泛使用&#xff0c;因为它能够有效地评估模型预测的概率分布与…...

wps 怎么显示隐藏文字

wps 怎么显示隐藏文字 》文件》选项》视图》勾选“隐藏文字” wps怎么设置隐藏文字 wps怎么设置隐藏文字...

Vue3 其它API Teleport 传送门

Vue3 其它API Teleport 传送门 在定义一个模态框时&#xff0c;父组件的filter属性会影响子组件的position属性&#xff0c;导致模态框定位错误使用Teleport解决这个问题把模态框代码传送到body标签下...

亚马逊玩具品类技术驱动型选品策略:从趋势洞察到合规基建

一、全球玩具电商技术演进趋势 &#xff08;技术化重构原市场背景&#xff09; 数据可视化分析&#xff1a;通过亚马逊SP-API抓取2023年玩具品类GMV分布热力图 监管技术升级&#xff1a; 美国CPSC启用AI质检系统&#xff08;缺陷识别准确率92.7%&#xff09; 欧盟EPR合规接口…...

SpringBoot3+EasyExcel通过WriteHandler动态实现表头重命名

方案简介 为了通过 EasyExcel 实现动态表头重命名&#xff0c;可以封装一个方法&#xff0c;传入动态的新表头名称列表&#xff08;List<String>&#xff09;&#xff0c;并结合 WriteHandler 接口来重命名表头。同时&#xff0c;通过 EasyExcel 将数据直接写入到输出流…...

PHY——LAN8720A 寄存器读写 (二)

文章目录 PHY——LAN8720A 寄存器读写 (二)工程配置引脚初始化代码以太网初始化代码PHY 接口实现LAN8720 接口实现PHY 接口测试 PHY——LAN8720A 寄存器读写 (二) 工程配置 这里以野火电子的 F429 开发板为例&#xff0c;配置以太网外设 这里有一点需要注意原理图 RMII_TXD0…...

HTML5和CSS3的一些特性

HTML5 和 CSS3 是现代网页设计的基础技术&#xff0c;它们引入了许多新特性和功能&#xff0c;极大地丰富了网页的表现力和交互能力。 HTML5 的一些重要特性包括&#xff1a; 新的语义化标签: HTML5 引入了一些重要的语义化标签如 <header>, <footer>, <articl…...

sass报错,忽略 Sass 弃用警告,降级版本

最有效的方法是创建一个 .sassrc.json 文件来配置 Sass 编译器。告诉 Sass 编译器忽略来自依赖项的警告消息。 解决方案&#xff1a; 1. 在项目根目录创建 .sassrc.json 文件&#xff1a; {"quietDeps": true }这个配置会让 Sass 编译器忽略所有来自依赖项&#x…...

DeepSeek+Kimi:PPT制作的效率革命

摘要&#xff1a;传统PPT制作面临模板选择困难、内容逻辑混乱、设计排版能力有限以及反复修改等问题。DeepSeek和Kimi两款AI工具的组合为PPT制作提供了全新的解决方案。DeepSeek擅长内容生成与逻辑推理&#xff0c;能够快速生成高质量的PPT大纲和内容&#xff1b;Kimi则专注于长…...

transformers中学习率warmup策略具体如何设置

在使用 get_linear_schedule_with_warmup&#xff08;如 Hugging Face Transformers 库中的学习率调度器&#xff09;时&#xff0c;参数的合理设置需要结合 数据量&#xff08;dataset size&#xff09;、批次大小&#xff08;batch size&#xff09; 和 训练轮数&#xff08;…...

linux实现rsync+sersync实时数据备份

1.概述 rsync(Remote Sync) 是一个Unix/linux系统下的文件同步和传输工具 2.端口和运行模式 tcp/873 采用C/S模式&#xff08;客户端/服务器模式&#xff09; 3.特点 可以镜像保存整个目录和文件第一次全量备份(备份全部的文件),之后是增量备份(只备份变化的文件) 4. 数…...

CTF类题目复现总结-[MRCTF2020]ezmisc 1

一、题目地址 https://buuoj.cn/challenges#[MRCTF2020]ezmisc二、复现步骤 1、下载附件&#xff0c;得到一张图片&#xff1b; 2、利用010 Editor打开图片&#xff0c;提示CRC值校验错误&#xff0c;flag.png应该是宽和高被修改了&#xff0c;导致flag被隐藏掉&#xff1b;…...

『Linux』 第十一章 线程同步与互斥

1. 线程互斥 1.1 进程线程间的互斥相关背景概念 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区互斥&#xff1a;任何时刻&#xff0c;互斥保证有且只有一个执行流进入临界…...

【数据结构】队列

目录 一、队列1、概念与结构2、队列的实现3、队列的初始化4、打印队列数据5、入队6、销毁队列7、队列判空8、出队9、取队头、队尾数据10、队列中有效元素个数 二、源码 个人主页&#xff0c;点击这里~ 数据结构专栏&#xff0c;点击这里~ 一、队列 1、概念与结构 概念&#x…...

【导航定位】GNSS数据协议-RINEX OBS

RINEX协议 RINEX(Receiver INdependent EXchange format,与接收机无关的交换格式)是一种在GPS测量应用中普遍采用的标准数据格式,该格式采用文本文件形式&#xff08;ASCII码&#xff09;存储数据数据记录格式与接收机的制造厂商和具体型号无关。目前RINEX版本已经发布到了4.x…...

Qt中的事件循环

Qt的事件循环是其核心机制之一&#xff0c;它是一种消息处理机制&#xff0c;负责处理各种事件(如用户输入、定时器、网络请求等)的分发和处理。Qt中的事件循环是一个持续运行的循环&#xff0c;负责接收事件并将它们分发给相应的对象进行处理。当没有事件需要处理时&#xff0…...

Android并发编程:线程池与协程的核心区别与最佳实践指南

1. 基本概念对比 特性 线程池 (ThreadPool) 协程 (Coroutine) 本质 Java线程管理机制 Kotlin轻量级并发框架 最小执行单元 线程(Thread) 协程(Coroutine) 创建开销 较高(需分配系统线程资源) 极低(用户态调度) 并发模型 基于线程的抢占式调度 基于协程的协作式调度 2. 核心差异…...

吴恩达深度学习复盘(2)神经网络的基本原理轮廓

笔者注 这两节课主要介绍了神经网络的大的轮廓。而神经网络基本上是在模拟人类大脑的工作模式&#xff0c;有些仿生学的意味。为了便于理解&#xff0c;搜集了一些脑神经的资料&#xff0c;这部分是课程中没有讲到的。 首先要了解一下大脑神经元之间结构。 细胞体&#xff1…...

【redis】集群 数据分片算法:哈希求余、一致性哈希、哈希槽分区算法

文章目录 什么是集群数据分片算法哈希求余分片搬运 一致性哈希扩容 哈希槽分区算法扩容相关问题 什么是集群 广义的集群&#xff0c;只要你是多个机器&#xff0c;构成了分布式系统&#xff0c;都可以称为是一个“集群” 前面的“主从结构”和“哨兵模式”可以称为是“广义的…...

计算机组成原理笔记(六)——2.2机器数的定点表示和浮点表示

计算机在进行算术运算时&#xff0c;需要指出小数点的位置&#xff0c;根据小数点的位置是否固定&#xff0c;在计算机中有两种数据格式:定点表示和浮点表示。 2.2.1定点表示法 一、基本概念 定点表示法是一种小数点的位置固定不变的数据表示方式&#xff0c;用于表示整数或…...

将树莓派5当做Ollama服务器,C#调用generate的API的示例

其实完全没这个必要&#xff0c;性能用脚后跟想都会很差。但基于上一篇文章的成果&#xff0c;来都来了就先简单试试吧。 先来看看这个拼夕夕上五百多块钱能达到的效果&#xff1a; 只要对速度没要求&#xff0c;那感觉就还行。 Ollama默认只在本地回环&#xff08;127.0.0…...

MYSQL数据库(一)

一.数据库的操作 1.显示数据库 show databases; 2.创建数据库 create database 数据库名; 3.使用数据库 use 数据库名; 4.删除数据库 drop database 数据库名; drop database if exists 数据库名; 二.表的操作 1.显示所有表 show tables; 2.查看表结构 des…...

Python Cookbook-4.15 字典的一键多值

任务 需要一个字典&#xff0c;能够将每个键映射到多个值上。 解决方案 正常情况下&#xff0c;字典是一对一映射的&#xff0c;但要实现一对多映射也不难&#xff0c;换句话说&#xff0c;即一个键对应多个值。你有两个可选方案&#xff0c;但具体要看你怎么看待键的多个对…...

IDEA 终端 vs CMD:为什么 java -version 显示的 JDK 版本不一致?

前言&#xff1a;离谱的 JDK 版本问题 今天遇到了一个让人抓狂的现象&#xff1a;在 Windows 的 CMD 里输入 java -version 和在 IntelliJ IDEA 终端输入 java -version&#xff0c;居然显示了不同的 JDK 版本&#xff01; 本以为是环境变量、缓存或者 IDEA 设置的问题&#x…...

Flask登录页面后点击按钮在远程CentOS上自动执行一条命令

templates文件夹和app.py在同一目录下。 templates文件夹下包括2个文件&#xff1a;index.html login.html app.py代码如下&#xff1a; import os import time from flask import Flask, render_template, request, redirect, session, make_response import mysql.con…...

深度解析:文件夹变白色文件的数据恢复之道

在数字化时代&#xff0c;数据的重要性不言而喻。然而&#xff0c;当我们在使用计算机时&#xff0c;偶尔会遇到一些棘手的问题&#xff0c;其中“文件夹变白色文件”便是一个令人困惑且亟待解决的难题。这一现象不仅影响了文件的正常访问&#xff0c;更可能隐藏着数据丢失的风…...

【Matlab】-- 基于MATLAB的飞蛾扑火算法与反向传播算法的混凝土强度预测

文章目录 文章目录 01 内容概要02 MFO-BP模型03 部分代码04 运行结果05 参考文献06 代码下载 01 内容概要 本资料介绍了一种基于飞蛾扑火算法&#xff08;Moth Flame Optimization, MFO&#xff09;与反向传播算法&#xff08;Backpropagation, BP&#xff09;的混凝土强度预…...

【Python实例学习笔记】图像相似度计算--哈希算法

【Python实例学习笔记】图像相似度计算--哈希算法 一、哈希算法的实现步骤&#xff1a;二、对每一步都进行注解的代码 一、哈希算法的实现步骤&#xff1a; 1、缩小尺寸&#xff1a; 将图像缩小到8*8的尺寸&#xff0c;总共64个像素。这一步的作用是去除图像的细节&#xff0c…...

2025DevSecOps标杆案例|智能制造国际领导厂商敏捷安全工具链实践

某智能制造国际领导厂商是涵盖智能家居、楼宇科技&#xff0c;工业技术、机器人与自动化和数字化创新业务五大业务板块为一体的全球化科技集团&#xff0c;连续入选《财富》世界500强&#xff0c;每年为全球超过4亿用户、各领域的重要客户与战略合作伙伴提供产品和服务。 数智化…...

【YOLOv11】目标检测任务-实操过程

目录 一、torch环境安装1.1 创建虚拟环境1.2 启动虚拟环境1.3 安装pytorch1.4 验证cuda是否可用 二、yolo模型推理2.1 下载yolo模型2.2 创建模型推理文件2.3 推理结果保存路径 三、labelimg数据标注3.1 安装labelimg3.2 解决浮点数报错3.3 labelimg UI界面介绍3.4 数据标注案例…...

第十七章:Python数据可视化工工具-Pyecharts库

一、Pyecharts简介 资源绑定附上完整资源供读者参考学习&#xff01; Pyecharts是一个基于百度开源可视化库ECharts的Python数据可视化工具&#xff0c;支持生成交互式的HTML格式图表。相较于Matplotlib等静态图表库&#xff0c;Pyecharts具有以下优势&#xff1a; 丰富的图表…...

解决【vite-plugin-top-level-await】 插件导致的 Bindings Not Found 错误

解决【vite-plugin-top-level-await】 插件导致的 Bindings Not Found 错误 环境设置 操作系统: macOS硬件平台: M1 Pro前端框架: Vue 3Node.js 版本: 20 在使用 Vue 项目时&#xff0c;我们尝试集成 vite-plugin-top-level-await 插件以支持顶层 await 语法。然而&#xff…...

《八大排序算法》

相关概念 排序&#xff1a;使一串记录&#xff0c;按照其中某个或某些关键字的大小&#xff0c;递增或递减的排列起来。稳定性&#xff1a;它描述了在排序过程中&#xff0c;相等元素的相对顺序是否保持不变。假设在待排序的序列中&#xff0c;有两个元素a和b&#xff0c;它们…...

六十天前端强化训练之第三十七天之Docker 容器化部署实战指南(大师级详解)

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、Docker 核心知识体系 1.1 容器革命&#xff1a;改变开发方式的技术 1.2 Docker 三剑客 1.3 Docker 生命周期管理 1.4 关键命令详解 二、前端容器化实战案例&#xff…...

RabbitMQ--延迟队列事务消息分发

目录 1.延迟队列 1.1应用场景 1.2利用TTL死信队列模拟延迟队列存在的问题 1.3延迟队列插件 1.4常见面试题 2.事务 2.1配置事务管理器 3.消息分发 3.1概念 3.2应用场景 3.2.1限流 3.2.2负载均衡 1.延迟队列 延迟队列(Delayed Queue)&#xff0c;即消息被发送以后, 并…...

列表,元组,字典,集合,之间的嵌套关系

在 Python 中&#xff0c;列表、元组、字典和集合的嵌套关系需要遵循各自的特性&#xff08;如可变性、可哈希性&#xff09;。以下是它们之间的嵌套规则、示例和典型应用场景的详细梳理&#xff1a; 1. 列表&#xff08;List&#xff09;的嵌套 特性&#xff1a; 可变、有序…...