在2010年路由器上运行Pixelflut

Lobsters Hottest 新闻

摘要

作者描述了如何使用OpenWRT并交叉编译Rust代码,在一台2010年的TP-Link Archer C7路由器上运行Pixelflut(一个协作像素艺术项目),并详细介绍了技术挑战和设置过程。

<p><a href="https://lobste.rs/s/ivm0qn/running_pixelflut_on_2010_router">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/24 23:06

# 在2010年的路由器上运行Pixelflut 来源:http://filmroellchen.eu/blog/mipselflut/ ## 搜索结果 \.\. (http://filmroellchen.eu/blog/)/mipselflut 发布于:2026\-06\-19 ## 目录 - 目标混淆 (http://filmroellchen.eu/blog/mipselflut/#target-confusion) - Breakwater崩溃 (http://filmroellchen.eu/blog/mipselflut/#breakwater-breaks) - 大端序回归 (http://filmroellchen.eu/blog/mipselflut/#return-of-the-big-endian) - 获取画布 (http://filmroellchen.eu/blog/mipselflut/#getting-the-canvas) - 不过说真的,ffmpeg... (http://filmroellchen.eu/blog/mipselflut/#actually-though-ffmpeg) - Kleines Filmröllchen的糟糕视频流 (http://filmroellchen.eu/blog/mipselflut/#kleines-filmrollchen-s-shitty-video-streaming) - 速率限制 (http://filmroellchen.eu/blog/mipselflut/#rate-limiting) - 成功 (http://filmroellchen.eu/blog/mipselflut/#success) - 脚注 (http://filmroellchen.eu/blog/mipselflut/#footnotes) 我参与Pixelflut领域已有数年。在AtGPN24 (https://entropia.de/GPN24) 上,包括我在内的一些成员成立了Pixelflut的“特别兴趣小组”,建立了Codeberg组织 (https://codeberg.org/pixelflut)、新网站 (https://pixelflut.org/),并开始起草RFC。与此同时,我入手了一台TP\-Link Archer C7 \(v2\)。这是一款简洁的一体式消费路由器,内置WiFi,特别值得注意的是它是一个得到良好支持的OpenWRT (https://openwrt.org/) 平台。难怪如此,其固件更新几乎不进行任何校验,因此你可以直接将OpenWRT刷入,重启后即可进入Linux系统。 于是某晚,我萌生了将两者结合的想法:在路由器上运行Pixelflut会怎样?路由器没有屏幕,因此运行Doom(毁灭战士)会很无聊。(考虑到只需编译一个超高可移植性的Linux Doom移植版,这可能还挺容易的。)那么,不如运行一些与网络相关的东西,而这正是路由器的本职工作。考虑到它只有一个700MHz的单核CPU和大约64MB内存可供实验,效果肯定*非常糟糕*,但它应该能运行起来!而且我可以通过网络将输出流回传到显示屏。 图1:*轻拍路由器*这台厉害的宝贝能塞下这么多像素 以下帖子将按时间顺序准确记述我在Archer C7上让Pixelflut运行起来的历程,包括我途中犯的所有错误以及学到的所有东西。 --- 我选择breakwater (https://github.com/sbernauer/breakwater) 作为Pixelflut服务器,原因如下: - 它是用Rust编写的,Rust可移植性很好。 - 我熟悉其代码库,可以轻松修改。 - 我与开发者是朋友,很可能可以直接提问,甚至提交PR :) - breakwater已经有一个“sink”插件系统,可以方便地添加其他输出。 ## 目标混淆 在我看来,OpenWRT基本就是Alpine Linux,使用musl (https://musl.libc.org/) C库。因此,我为`aarch64\-unknown\-linux\-musl`交叉编译了breakwater,只需简单地指定`cargo build \-\-target aarch64\-unknown\-linux\-musl \-\-release`。 如果你还不知道,这个神奇的字符串被称为“目标描述符”、“目标标识符”或“目标三元组”,因为很明显,它包含四个部分: - CPU架构。此处:Aarch64,即64\-位ARM。 - 供应商。此处:我不知道Linus Torvalds是谁。 - 操作系统。此处:Linux。 - C库及其调用约定。此处:musl libc。 目标描述符告诉你正在为哪个目标编译代码,这在进行类似此处的交叉编译时尤为重要。举个例子,当今桌面系统最常见的三个目标分别是`x86\_64\-pc\-windows\-msvc`、`aarch64\-apple\-darwin`和`x86\_64\-unknown\-linux\-gnu`。如果你同时使用Rust和Web,可能也听说过`wasm32\-unknown\-unknown`。但也许有一天你真的想用Rust开始开发任天堂3DS游戏,那么你就得用`armv6k\-nintendo\-3ds`。或者你工作在某个神秘地方,需要`sparcv9\-sun\-solaris`。无论如何,你都需要识别正确的编译目标。 而这正是我没有做对的地方。 因为经过进一步研究,我发现Archer C7中的处理器——高通Atheros QCA9558(即OpenWRT中的ath79 (https://openwrt.org/docs/techref/targets/ath79) 平台)——既不是64\-位ARM核心,也不是32\-位ARM核心。(它显然不是x86,否则我会更惊讶。) 它是MIPS。一款实现MIPS32 Release 2和MIPS16e的24Kc系列MIPS核心。支持大端序和小端序,无硬件浮点,32个寄存器,体现RISC的精髓。这是一个现已消亡的架构,曾用于PlayStation 1和2、任天堂N64等经典游戏机,以及从2000年代到2010年代初的大量嵌入式系统。显然,24K曾是MIPS历史上最成功的核心系列之一。安息吧,MIPS,1984\-2021。它最大的成就可能不是其架构中可见的分支延迟槽,而是其对SPARC、ARM以及最重要的RISC\-V的巨大影响。 此刻,我对这个项目更加期待了。我们不仅拥有一个过时的架构,而且很可能还能读懂它,因为它与我了如指掌的RISC\-V架构共享许多指令助记符和整体操作原理。 MIPS远非冷门,因此Rust编译器支持相当不错。有好几个目标可供选择。我需要哪一个? ``` root@Vodkafone:~# uname -a Linux Vodkafone 6.12.87 #0 Wed May 13 22:42:09 2026 mips GNU/Linux ``` `mips`,这——没什么帮助。 ``` root@Vodkafone:~# file /bin/busybox /bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mips-sf.so.1, no section header ``` 谢谢你帮我查阅OpenWRT文档。 实际上,我花了大约两个小时尝试不同方法才弄明白: - 我尝试为`mipsel\-unknown\-linux\-musl`编译,这需要我构建一个自定义的Rust编译器,而后者又需要构建相应的GCC编译器,但我未能找到一个好的来源(AUR让我失望了)。 - 不知为何我尝试了`\-gnu`目标,但可以预料的是,当它确实需要glibc时我就卡住了,我无法编译它,即使有AUR的一些额外帮助也不行。(这有大量依赖,比如特定目标的Linux头文件,这实际上需要你进行部分Linux内核构建。) - 我实际上找对了目标,但以为我的Rust编译器没有包含它,于是我又花了一段时间重新编译自定义`rustc`,这次编译器试图为无浮点支持的处理器生成浮点指令: 图2:我不知道`ldc1`是什么指令,但`f0`看起来确实像浮点寄存器,而`$4`=`x4`是栈指针。终于为我那些RISC\-V知识找到了用武之地! - 我意识到我还需要一个链接器,最终重新发现了musl\-cross (https://musl.cc/),于是我快速修改了AUR的aarch64 musl cross (https://aur.archlinux.org/packages/aarch64-linux-musl-cross-bin) 包,改为安装`mips`版本。 - `breakwater\-parser\-c\-bindings`仍然有问题;你将在下文看到`-\-package breakwater`选项。 为了完整解释这一点(因为在最初的三个小时尝试中,这一点对我来说也不明显):MIPS是一个庞大的架构家族,也包括一个64\-位变种。这显然是32\-位变种,但从1984年到约2010年,存在许多不同版本的32\-位MIPS。最重要的是,所有32\-位MIPS处理器都支持*双端序*(bi\-endianness),意味着它们可以根据各种设置在小端模式或大端模式下运行。在QCA9558上,只支持大端模式;或者至少Linux和OpenWRT只使用大端模式(我没有进一步检查)。无论如何,出于一些令人困惑的原因,大端MIPS在目标标识符中被称为`mips`,而小端MIPS被称为`mipsel`。我在此正式将此项目命名为*MIPSelflut*,即使它实际上并不使用MIPSel。 ## Breakwater崩溃 总之,在经过所有这些捣鼓和研究之后,我终于意识到正确的目标*是*官方rustup rustc内置的,你只需要构建自己的标准库。由于breakwater本来就在使用nightly版本,我甚至不需要切换工具链,我只需要: ``` $ cargo build -Zbuild-std --config 'target.mips-unknown-linux-musl.linker="mips-linux-musl-gcc"' --target mips-unknown-linux-musl --release --no-default-features --package breakwater -------- snip -------- error[E0432]: unresolved imports `std::sync::atomic::AtomicI64`, `std::sync::atomic::AtomicU64` --> /home/kleines/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/prometheus-0.13.4/src/atomic64.rs:7:25 | 7 | use std::sync::atomic::{AtomicI64 as StdAtomicI64, AtomicU64 as StdAtomicU64, Ordering}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ no `AtomicU64` in `sync::atomic` | | | no `AtomicI64` in `sync::atomic` | = help: consider importing this struct through its public re-export instead: crate::core::AtomicI64 = help: consider importing this struct through its public re-export instead: crate::core::AtomicU64 help: a similar name exists in the module | 7 - use std::sync::atomic::{AtomicI64 as StdAtomicI64, AtomicU64 as StdAtomicU64, Ordering}; 7 + use std::sync::at -------- snip -------- error: could not compile `prometheus` (lib) due to 3 previous errors ``` 啊,好吧,那会太容易了。显然,32\-位MIPS不会有64\-位原子操作(事实上,我很惊讶它甚至有32\-位原子操作)。但就编译器错误而言,这实际上就是全部了:一旦我通过功能标志将prometheus功能移除,它就能编译了。 将二进制文件传输到路由器本身就是一个挑战:路由器闪存非常有限,所以我绝对不想把3.5MB的breakwater二进制文件放在那里。经过一番摸索,我让USB闪存驱动器工作了,现在我有64GB的临时空间。然而,总是插拔USB驱动器有点麻烦,而且没有SFTP(即`scp`不起作用),因此我想出了以下技巧: ``` cat target/mips-unknown-linux-musl/release/breakwater | ssh root@vodkafone ash -c 'tee > /mnt/somedrive/breakwater' ``` 这个技巧非常经典,在我看来在系统管理员中广为人知。如果你想让大文件更高效,可以在ssh管道的两端都使用压缩二进制。`sha256sum`确认这也没有引入任何不需要的换行符。 好,开始: ``` root@Vodkafone:/mnt/somedrive# chmod +x breakwater root@Vodkafone:/mnt/somedrive# file ./breakwater ./breakwater: ELF 32-bit MSB pie executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mips.so.1, not stripped root@Vodkafone:/mnt/somedrive# ./breakwater -ash: ./breakwater: not found ``` ... 抱歉?二进制文件*就在那儿*,你这笨蛋? 我不确定原因,但这触发了我模糊的记忆,或者只是我通用的Linux知识。如果你曾经在一个可执行文件上遇到这种错误——文件类型正确,位于正确的目录——你可能知道问题所在。我很快证实了我的怀疑: ``` root@Vodkafone:/mnt/somedrive# file /bin/busybox /bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mips-sf.so.1, no section header ``` 剧透警告(如果你想自己找出问题):动态链接器(即“解释器”)错了。busybox正确使用了`/lib/ld\-musl\-mips\-sf\.so\.1`,而我新编译的breakwater使用了`/lib/ld\-musl\-mips\.so\.1`。区别在于中间的`\-sf`。据我所知,它代表`softfloat`(软浮点);因为这个处理器不支持浮点,浮点操作是通过软件模拟的。我查看了编译日志,它甚至警告目标使用软浮点。Rust构建系统内部似乎对使用软浮点还是硬浮点有些混淆;Rust目标文档指定这应该是一个默认软浮点的目标。考虑到大多数较旧的MIPS处理器(该目标仍然支持它们)没有浮点支持,就像24Kc一样,这很合理。 无论如何,通过在`RUSTFLAGS`中覆盖动态链接器可以快速修复: ``` RUSTFLAGS='-Clink-arg=-Wl,--dynamic-linker=/lib/ld-musl-mips-sf.so.1' cargo build -Zbuild-std --config 'target.mips-unknown-linux-musl.linker="mips-linux-musl-gcc"' --target mips-unknown-linux-musl --release --no-default-features --package breakwater ``` 开始: ``` root@Vodkafone:/mnt/somedrive# file ./breakwater breakwater: ELF 32-bit MSB pie executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mips-sf.so.1, not stripped root@Vodkafone:/mnt/somedrive# ./breakwater -f 10 --network-buffer-size 64000 2026-06-15T20:26:17.631397Z INFO new{listen_addresses=[[::]:1234] network_buffer_size=64000 max_connections_per_ip=None}: breakwater::server: started Pixelflut server ``` 这是一个可以工作的breakwater!在MIPS上! ...它除了`PX`get之外没有其他方式输出画布。 而且它实际上也不工作。我的Pixelflut客户端hyperflut表示无法读回画布大小。手动尝试`nc`,服务器就是不响应,尽管第一轮测试表明连接明显正常,所以机器之间的TCP本身没问题。breakwater监听所有公共IPv6地址,与我可以测试的所有其他系统服务相同(例如SSH)。那里没有问题。 然后我开始调试接收逻辑,查看接收到了什么数据以及解析器对此说了什么。立刻,我有了顿悟。 ``` 2026-06-15T20:51:17.212134Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: handling new connection 2026-06-15T20:51:19.255604Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[72, 69, 76, 80, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:19.646435Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[69, 76, 80, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:19.925548Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[76, 80, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:42.340922Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[80, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:43.443933Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:43.546475Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:44.391550Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:44.866467Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:45.474012Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:45.897812Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:46.471996Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:46.953748Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:47.557784Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:48.053634Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:48.684178Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:49.196084Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:49.815445Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:50.336727Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:50.943684Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:51.466788Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:52.083317Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2026-06-15T20:51:52.590773Z DEBUG handle_connection{ip=2a04:6ec0:271:e850:f420:9a86:97fe:2fb7 network_buffer_size=64000}: breakwater::server: read data buffer=[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0,

相似文章

@realfxw: 出门在外想随时连家里的 NAS、调一下台式机里的 Ollama,或者开 Moonlight 串流,最烦这几件事: 没有公网 IPv4、大内网 NAT 环境复杂、开路由器端口映射又怕天天被全网脚本扫爆。 试试 Rust 写的轻量私有组网工具…

X AI KOLs Timeline

Lantunnel是一个用Rust编写的轻量私有组网工具,允许用户在无公网IPv4或复杂NAT环境下,安全访问家庭NAS、远程调用Ollama或进行游戏串流,通过P2P直连和加密中继避免端口暴露。

Qwen3.8-Flash-Next 宇宙街机随拍生成游戏测试

Reddit r/LocalLLaMA

本文详述了在本地 Intel V620 GPU 上测试运行 Qwen3.8-Flash-Next AI 模型的实践,使用 OMP 工具链,模型依据一个粗略的提示词在约3小时内生成了一款3D游戏。