先说这个项目是干什么的。AnyPS5 不是一台上古神机,也不是什么破解套件,它是我给自己手边几台 PS5 做的一个局域网辅助控制台。如果你也攒了不止一台 PS5,或者经常要在不同房间来回换着玩,应该能理解那种状态:游戏库到底哪个账号在哪个机器上、硬盘还剩多少、谁在待机、想串流还得先跑到另一台主机面前按开机键……这些东西平时没有一个统一入口去查看。
AnyPS5 的价值就是把这一摊子事汇总到一个 Web 页面里。我在浏览器里打开面板,就能看到每台主机的在线状态、存储余量、正在运行的游戏,还能一键触发唤醒、拉起官方 Remote Play 串流入口。整个项目不改主机系统、不碰任何安全边界,全部基于官方能力加上局域网内可以公开拿到的设备信息。自己玩玩也好,做成一个小工具给圈子里的朋友用也好,都是比较省心的方案。
1. 项目到底做什么:从“翻柜子确认主机状态”到“AnyPS5”
1.1 多主机玩家的日常痛点
我最早做这个项目的动机很简单:家里不止一台 PS5。客厅一台,书房一台,卧室偶尔也想躺着玩一会。问题就来了,每台机器上登录的账号不一样,下载的游戏也不一样,经常会出现“走到书房发现想玩的游戏在客厅那台机器上”的情况。
存储焦虑更常见。PS5 的硬盘看着很大,但几个大作装下来就快满了。每次想看剩余空间,都得开机进系统设置,一层层菜单翻到存储选项,在几个设备标签之间来回切换,这个体验放在 2024 年真的说不过去。再加上 Remote Play 串流虽然方便,但官方客户端在切换多台主机时并不顺手,我得先在手机上点连接,再去主机上确认,一来一回比直接跑到客厅开机还慢。
所以我当时给自己列了一个需求清单:能在电脑或手机浏览器里看到所有主机的在线状态;能确认每台主机当前在跑什么游戏;能快速发起串流;能记录每台主机的游戏库归属和存储余量。AnyPS5 就是围绕这几件事做的。
1.2 边界和底线:只做包装,不做破解
在动手之前,我先把底线划清楚了。AnyPS5 不做任何破解、越狱、系统级改动,也不会去抓那些需要绕过官方认证才能拿到的数据。原因很现实:个人项目首先是求稳。你改完系统可能玩两天就出问题,机器变砖或者被官方限制登录,代价比省那一点便利高多了。
那用什么方式拿数据?很简单:一靠局域网内公开广播的服务信息,PS5 待机时也会在网络里暴露一些设备服务描述,这些内容不需要登录,就像你家里那台智能音箱能被扫描到一样;二靠官方 Remote Play 已经开放的串流入口,我们只是把它从“打开 App 选设备”变成“打开网页点卡片”;三靠玩家半自动维护的台账,比如存储余量、游戏归属这类官方没开放 API 的数据,就设计成手动录入或定期核对。
这个思路可能不够“极客”,但它足够安全。AnyPS5 本质上是给官方能力做了一层聚合和美化,不越权,也就不会给自己挖坑。
1.3 整体设计思路
AnyPS5 分三个模块:设备发现模块、状态监控模块、快捷入口模块。设备发现模块负责在局域网里找到 PS5 并记录 IP、MAC、服务端口;状态监控模块定时探测主机是开机、待机还是离线,并汇总前一次已知状态;快捷入口模块则是把 Remote Play 拉起到指定设备,以及展示玩家手动更新的存储台账。
技术选型上,我用 Node.js 写后端,因为 UDP 组播这部分用事件驱动模型写起来非常顺手;前端直接用 Vue 3,但说实话用原生页面也够了,核心就是一个仪表盘加几张卡片。数据库没有上 MySQL,用 SQLite 存设备台账和状态历史,个人项目完全足够,备份也就拷一个文件的事。
2. 核心技术点拆解:它怎么知道 PS5 在哪、在干什么
2.1 局域网设备发现:mDNS/SSDP 加指纹识别
PS5 在局域网里并不是隐形设备。它会通过 UPnP/SSDP 或者类似的组播协议广播自己的服务信息,只要我们在同一个网段,发送一个标准搜索报文,它就会回复自己的设备描述地址。
我用的方式很简单,UDP 组播到239.255.255.250:1900,发送 SSDP 搜索请求,然后监听所有响应。家里网络环境里能响应的设备非常多,智能电视、路由器、音箱、甚至部分微波炉都会回复,所以关键一步是过滤出 PS5 的特征。这一步没有统一标准,不同固件版本的广播字段可能不太一样,我的做法是先把所有响应日志抓下来,找到远程游玩服务相关的特征字符串,再根据服务描述里的厂商和设备类型字段做匹配。
一个常见的坑是:PS5 可能不按标准的 SSDP 格式响应,而是用 mDNS 协议走224.0.0.251:5353。所以我在 AnyPS5 里同时做了两组探测,一组发 SSDP 广播,另一组发 mDNS 查询,然后把结果合并去重。如果你自己做类似项目,我建议也从这两条路入手,总有一条能扫到你的主机。
2.2 待机唤醒:不拆机,靠网络触达
PS5 在待机模式下并不是完全断网的。它依然会保留部分网络服务,用来响应官方 App 的远程启动指令。但在自己写的 Web 面板里,直接去调官方启动链路比较复杂,也不适合放进一个个人项目里。我采取的办法是“双轨并行”。
第一轨是局域网唤醒按钮。这个按钮会尝试向主机的 MAC 地址发送一条标准的 Wake-on-LAN 魔术包。某些 PS5 在待机模式下对标准 WOL 的支持并不一直稳定,但这招成本极低,值得保留;如果主机不响应,就换第二轨,也就是深层链接:AnyPS5 直接拉起本机的官方 Remote Play 客户端,并带着目标设备的信息,官方客户端会自动去唤醒主机。虽然还是要在电脑或手机上装一次官方 App,但体验比打开 App 再手动选设备顺畅得多。
这里要特别说明,我没有抓取任何绕过官方认证的唤醒协议。官方 App 能唤醒主机是因为用户已经登录了同一个账号,这是官方的正常能力,AnyPS5 只是把“点击唤醒”这个动作封装成了一个按钮。
2.3 运行状态和存储数据从哪来
说到“当前在线状态”,AnyPS5 实际上做的是对主机服务端口的连通性探测。主机开机状态下,远程游玩服务端口是打开的;待机时这个端口通常会关闭,但主机的网络栈还在;彻底关机后直接无响应。组合这三个结果,就能区分出“开机”“待机”“离线”三种基本状态。
存储余量和游戏库归属这一类数据,官方没有开放本地管理 API,所以我一开始就放弃了全自动拿数据的想法。AnyPS5 的做法是做一个“人工辅助台账”:你在系统设置里看一眼剩余空间,顺手在面板里填上数字,面板会记录这次更新的时间。这样做虽然没有实时性,但对你自己的几台设备来说,一周核对一次完全够用了。我更推荐的做法是,顺便在备注里写清楚这台机器主要放什么类型的游戏,避免下次又走错房间。
2.4 串流入口聚合
Remote Play 是官方功能,支持 PC、Mac、手机和平板。官方客户端的问题是设备多了以后,每次连接都要重新选主机,网络里有多台设备时还容易出现名字混淆。AnyPS5 的解决方案是在面板上给每台主机一张卡片,卡片上直接放“启动串流”按钮,按钮通过 URL Scheme 或自定义协议参数把官方客户端拉起来,让它自动连到指定的那台机器。
串流效果好不好,跟 AnyPS5 本身关系不大。局域网内我建议主机插网线、电脑或手机用 5GHz Wi-Fi;跨网串流则取决于上行带宽和网络环境,这一块我没在项目里做过任何加速或中转,因为那是官方客户端的能力范围。AnyPS5 能做的只是帮你把入口集齐,减少每次连接前的操作。
3. 实操过程:从零搭一个 AnyPS5 控制台
3.1 工程结构和依赖
AnyPS5 的工程结构很简单,我贴一个目录参考:
anyps5/ ├── package.json ├── server/ │ ├── index.js │ ├── discover.js │ ├── probe.js │ └── db.js ├── web/ │ ├── index.html │ ├── app.js │ └── style.css └── data/ └── devices.json后端依赖不多,就是express提供 REST API,sqlite3存台账,dgram是 Node.js 自带的 UDP 模块,不需要额外装包。前端我用 Vue 3 的 CDN 版本,没有引入构建工具,主要是想保持整个项目的轻量。Process 管理用pm2,部署在自己书房那台迷你主机上,开机自启。
选 Node.js 不只是因为顺手。UDP 组播监听是事件驱动的,Node 的异步模型处理这种网络探测很自然,不会像同步脚本那样监听组播时卡住其他请求。如果你更喜欢 Python,用 FastAPI 加asyncio也能做,只是前端静态服务这块要稍微多配一下。
3.2 设备发现模块
设备发现是 AnyPS5 最核心的模块。我先写一个最简单的 SSDP 探测函数:
const dgram = require('dgram'); function ssdpDiscover(timeout = 3000) { return new Promise((resolve) => { const socket = dgram.createSocket('udp4'); const results = []; socket.on('message', (msg, rinfo) => { const text = msg.toString('utf8'); if (text.includes('PLAYSTATION') || text.includes('PlayStation')) { results.push({ ip: rinfo.address, port: rinfo.port, headers: text }); } }); socket.bind(() => { socket.setBroadcast(true); const search = Buffer.from( 'M-SEARCH * HTTP/1.1\r\n' + 'HOST: 239.255.255.250:1900\r\n' + 'MAN: "ssdp:discover"\r\n' + 'MX: 1\r\n' + 'ST: ssdp:all\r\n' + '\r\n' ); socket.send(search, 0, search.length, 1900, '239.255.255.250'); }); setTimeout(() => { socket.close(); resolve(results); }, timeout); }); }这段代码只做了响应文本里的关键字过滤。实际项目里,最好再去获取设备描述文件,因为有些 PS5 响应头里不直接带 PlayStation 字样,而是在描述文件里带。描述文件通常是一个 XML,顺着响应里的LOCATION字段去访问,然后从 XML 里提取friendlyName和modelName。
过滤规则我总结成了一个函数,匹配条件包括:设备类型字段、服务描述里的远程游玩服务 ID、以及设备名称里的 PS5 相关标识。这套规则要留可配置的口子,因为系统更新后字段名可能会变。我就在配置里放了一份 JSON 规则文件,每次从抓包日志里发现新变化,改配置文件就行,不用改主程序。
3.3 状态轮询与前端仪表盘
设备发现只是完成“找到主机”,状态轮询才是让面板活起来的东西。我的做法是每 30 秒遍历一次已记录设备,对每台主机的服务端口做一次 TCP 连接测试。如果连接成功,判定为“开机”;如果连接超时,再尝试 ICMP Ping,判断主机网络栈是否还在,进一步区分待机和关机。
前端的仪表盘不需要太花哨。用卡片视图展示每台主机,每张卡片包含设备名、IP 地址、在线状态、存储余量、最近在线时间以及操作按钮。在线状态用一个小圆点表示,绿色开机、黄色待机、灰色离线。操作按钮两个,“串流”和“唤醒”。如果主机在线,串流按钮就是亮的;如果离线,唤醒按钮优先。
我用setInterval调/api/devices接口刷新数据,前端页面里做一个简单状态管理对象,收到新数据后对比变化,只更新有变化的卡片。这样不需要引入复杂框架,也能做到低延迟刷新。
这种仪表盘形式很吃网络环境的稳定性。如果你跟我一样把面板跑在一个 Docker 容器里,记得在容器里关闭防火墙对 UDP 组播的限制。我最初就是没注意这个,导致面板能展示台账,但死活扫不到设备。
3.4 数据台账与设备绑定
AnyPS5 的设备台账分成两半:自动发现的部分和手动维护的部分。自动发现的数据在每次探测后更新,比如 IP、服务端口、上次在线时间。手动维护的数据包括设备昵称、归属账号、存储总容量、已用容量、备注信息。
我建了一张表,字段大概是这样的:
| 字段 | 说明 | 更新方式 |
|---|---|---|
| device_id | 设备唯一标识 | 自动生成 |
| name | 设备昵称,比如“客厅主力机” | 手动 |
| owner | 归属账号名 | 手动 |
| ip | 当前局域网 IP | 自动 |
| mac | 网络唤醒使用的 MAC | 自动/手动复核 |
| service_port | 远程游玩服务端口 | 自动 |
| storage_total | 存储总容量 | 手动 |
| storage_used | 已用容量 | 手动 |
| last_seen | 最近一次在线时间 | 自动 |
| notes | 备注 | 手动 |
手动维护是故意的。因为没有官方 API 的情况下,任何声称能自动读取 PS5 存储余量的做法都站不住脚。与其做一个靠猜的数据,不如明明白白标注“上次手动更新”。我在表单里加了一个“更新时间”字段,下次打开面板时扫到老数据就会提醒我去核对一次。
4. 踩过的坑和排查清单
4.1 设备发现失败
做 AnyPS5 过程中遇到最多的就是设备扫不到。排查下来,原因几乎集中在三块:网段隔离、组播被拦、响应被过滤。
路由器开了 AP 隔离的话,设备之间直接互相不可见,组播包发得出去但收不回来,这时候先在路由器后台关掉 AP 隔离,或者在同一个交换机下测试。第二种情况是主机在 5GHz Wi-Fi、电脑在 2.4GHz Wi-Fi,虽然同一个路由器但不保证组播互通,建议把测试设备都接有线或者放到同一频段。第三种最常见,也就是我的过滤规则写得太死,把 PS5 的响应包给排掉了。
解决方法是把响应日志先完整打印出来跑一天,看看你的主机回复的字段到底长什么样,再据此调整过滤规则。
4.2 串流拉不起来
串流按钮点了没反应,先别怪 AnyPS5,八成是 Remote Play 客户端本身的问题。第一个检查点是客户端必须登录跟主机相同的账号;第二个是主机不能处于彻底关机状态,Remote Play 只能唤醒待机模式的机器;第三个是手机或电脑上的 Remote Play 版本太旧,旧版本在设备切换上表现很差。
我还在面板里加了一行提示,如果主机状态是“离线”,串流按钮会直接置灰。因为对彻底关机的主机,点十次也是白点。
4.3 主机状态误判
只依赖 TCP 端口判断状态会有一个错觉:待机状态下某些服务的端口可能半开,导致面板把待机误判成开机。我后来加入了一个“连续两次成功才算开机”的逻辑,减少单次探测的抖动。
主机刚开机那几秒,网络服务没有完全起来,也会出现探测失败。所以我对“开机”状态的定义不是绝对事实,而是“过去一段时间内持续可连接”,这样界面上的状态不会频繁跳变。
4.4 系统更新后行为变化
PS5 系统一更新,设备描述文件、服务端口、甚至广播协议都可能变化。我遇到过更新后设备描述文件访问超时的情况,整个发现模块直接失效。后来我把所有外部交互都做了容错,解析字段时用正则匹配尽量宽松,找不到目标字段就跳过而不是抛异常。日志里每天记录一次抓到的原始响应,以备对比。
5. 后续还能怎么玩
AnyPS5 目前是一个纯局域网工具,我还在折腾的方向有几个。一个是多用户共享,家里其他人也能打开面板,各自看到自己账号对应的设备,避免点错启动串流。另一个是串流质量检测,在发起串流之后记录一下当前网络的 RTT 和丢包率,至少能帮你判断是路由器位置问题还是网络问题。
我还打算把存储台账做成周期提醒。每两周面板弹一条消息,让你去核对一次剩余空间,慢慢养成习惯,就不会出现“想下载新游戏才发现硬盘满了一周”的情况了。
最后分享一点我做这个项目最大的体会:越是想解决游戏玩家的繁琐操作,越要克制住“什么都要管”的冲动。AnyPS5 的重点不是去接管 PS5,而是给玩家一个更好的视图。我自己用了两个多月,最顺手的就是晚上躺在床上直接点开卡片启动串流,不用再去客厅按开机键。这个项目后续我还会继续加串流码率监测和家庭共享账单,目前正在折腾。如果你也在玩 PS5,建议你也试试把端口和服务广播抓一抓,很多看似封闭的系统,在局域网里其实给了你不少可用的缝隙。