ARTICLE · 1029486
dtnsbot API 更新说明(整合dtns.rpc-fast之e2ee和NAT内网穿透通讯能力)
dtnsbot API 更新说明(整合dtns.rpc-fast之e2ee和NAT内网穿透通讯能力)
dtns.rpc-fast 技术整合公告
版本:v2.0(WebRTC RPC) 发布日期:2026-09-18 影响范围:新增 WebRTC RPC 通道,HTTP API 完全兼容,无需改动
一、更新摘要
dtnsbot 在保持原有 HTTP API(http://[设备IP]:58082/api/?command=...)不变的前提下,新增了基于 WebRTC 的 RPC 通道。这项能力的核心是集成了 dtns.rpc-fast 技术栈,使得:
- 所有 HTTP 命令
都可以通过 WebRTC 调用,命令语义完全一致 - 文件传输
从"Base64 over HTTP"升级为"二进制分片 over WebRTC",支持 GB 级文件 - NAT 穿透
无需公网 IP、无需端口映射,跨网络直连 - 断点续传 / 动态切片 / 服务端驱动重发
网络抖动下自动恢复 - 大 JSON 自动 gzip 压缩
带宽节省最高 90%
HTTP API 用户无需任何改动,可直接继续使用。

二、为什么要整合 dtns.rpc-fast
2.1 原有 HTTP API 的局限
| 需要公网 IP / 端口映射 | |
| 文件走 Base64 | |
| 单次请求 body 限制 | |
| 无进度、无断点续传 | |
| 大 JSON 无压缩 |
2.2 dtns.rpc-fast 带来的能力
| P2P NAT 穿透 | |
| 二进制分片传输 | |
| GB 级文件支持 | |
| 断点续传 | streamId |
| 动态切片 | |
| 服务端驱动重发 | STREAM_RETRY |
| 大 JSON gzip 压缩 | |
| E2EE 传输加密 |
三、dtns.rpc-fast 技术架构
3.1 整体分层
┌─────────────────────────────────────────────────────────┐│ 应用层:dtnsbot 命令处理(onCommandReceived) │├─────────────────────────────────────────────────────────┤│ 协议层:dtns.rpc-fast ││ - RPC 帧:REQ / RES / ERR / STREAM / ACK / RETRY ││ - 分片:动态切片 + 滑动窗口 + 停滞检测 ││ - 存储抽象:sink / source 接口 │├─────────────────────────────────────────────────────────┤│ 传输层:WebRTC DataChannel (SCTP over DTLS) ││ - 强制加密 (DTLS-SRTP) ││ - 可靠传输 (SCTP ordered mode) ││ - NAT 穿透 (STUN/TURN/ICE) │├─────────────────────────────────────────────────────────┤│ 信令层:Socket.IO + simple-signal ││ - SDP / ICE 交换 ││ - 房间发现 │└─────────────────────────────────────────────────────────┘3.2 关键设计
① 上传当反向下载
上传和下载在协议层完全对称:
| 下载 | ||
| 上传 |
同一套 StreamPusher / StreamReceiver 类,角色互换即完成上传/下载。
② 动态切片
③ 服务端驱动重发
Android 端检测到坏片/丢片 → 主动发 STREAM_RETRY客户端只重发对应分片,其他不动 停滞 5 秒无进展 → 主动要求重发下一片
④ 大 JSON 自动降级 + 压缩
结果 JSON ≤ 16KB → RES 直接返回结果 JSON > 16KB → gzip (JSZip) → 走 stream 通道结果 JSON > 256MB → 报错(避免 OOM)⑤ 存储抽象
- Android
AndroidDownloadSink→ JS 桥接 JavaRandomAccessFile - 浏览器
OpfsDownloadSink→ OPFS(Origin Private File System) - Node
FsDownloadSink→fs.writeSync - 内存
MemoryDownloadSink→ 兜底
四、新增 API 概览
4.1 WebRTC 管理命令(HTTP 调用)
这些命令通过原有 HTTP API 调用,用于控制 WebRTC 行为:
webrtc_server_start | |
webrtc_server_stop | |
webrtc_client_start | |
webrtc_client_stop | |
webrtc_set_signal&url=... | |
webrtc_set_server_room&room=... | |
webrtc_set_client_room&room=... | |
webrtc_status | |
webrtc_rpc_call&url=...¶ms=... | |
webrtc_rpc_upload&url=...&path=... | |
webrtc_rpc_download&url=...¶ms=...&save=... |
示例:
# 配置信令curl "http://127.0.0.1:58082/api/?command=webrtc_set_signal&url=http://dev.dtns.top"# 配置 Server 房间curl "http://127.0.0.1:58082/api/?command=webrtc_set_server_room&room=room-android-001"# 启动 Servercurl "http://127.0.0.1:58082/api/?command=webrtc_server_start"# 查询状态curl "http://127.0.0.1:58082/api/?command=webrtc_status"4.2 WebRTC RPC 通道
通过 WebRTC 连接后,可调用以下 RPC 接口:
/command | /api/?command=... | 所有 HTTP 命令 |
/file/get | file_download | |
/file/put | file_upload | |
/file/list | file_list |
关键:/command 内部调用同一个 onCommandReceived,因此 HTTP 命令全部自动可用。
4.3 命令通道对照表
GET /api/?command=home | call('/command', { command: 'home' }) |
GET /api/?command=click_at_500,800 | call('/command', { command: 'click_at_500,800' }) |
GET /api/?command=set_config&key=k&value=v | call('/command', { command: 'set_config', params: { key: 'k', value: 'v' } }) |
GET /api/?command=get_screenshot_direct&quality=60 | call('/command', { command: 'get_screenshot_direct', params: { quality: '60' } }) |
GET /api/?command=file_download&path=... | download('/file/get', { path: '...' }) |
GET /api/?command=file_upload&... | upload(file, '/file/put', { path: '...' }) |
GET /api/?command=file_list&path=... | call('/file/list', { path: '...' }) |
五、使用示例
5.1 浏览器端接入
<script src="socket.io.min.js"></script><script src="simple-signal-client.min.js"></script><script src="jszip.min.js"></script><script src="rpc-protocol.js"></script><script src="rpc-core.js"></script><script src="opfs-utils.js"></script><script src="storage-browser.js"></script><script>const SSC = window.SimpleSignalClient || window.SimpleSignal;const client = new RPCCore.RPCClient( 'room-android-001', // Android 端配的 room 'http://dev.dtns.top', // 信令服务器 {}, { socketIo: io, SimpleSignalClient: SSC, rtcOptions: { iceServers: [ { urls: 'turn:static.dtns.top:3478' }, { urls: 'stun:stun.l.google.com:19302' }, ], }, createDownloadSink: () => new BrowserStorage.OpfsDownloadSink({ dir: 'downloads' }), wrapUploadSource: (src) => src instanceof Blob ? new BrowserStorage.FileUploadSource(src) : src, });await client.connect();console.log('connected to Android');// 调用 HTTP 命令(与 /api/?command=home 等价)await client.call('/command', { command: 'home' });// 截图const shot = await client.call('/command', { command: 'get_screenshot_direct' });console.log(shot.data); // base64// OCRconst ocr = await client.call('/command', { command: 'get_screenshot_ocr' });console.log(ocr.data.data.text);// 下载文件(二进制流,无 Base64)const dl = await client.download( '/file/get', { path: '/sdcard/Download/test.png', name: 'test.png' }, null, (got, total) => console.log(`${got}/${total}`));console.log('saved:', dl.url);// 上传文件const file = fileInput.files[0];const up = await client.upload( file, '/file/put', { path: '/sdcard/Download/', filename: file.name }, (acked, total) => console.log(`${acked}/${total}`));console.log('uploaded to:', up.path);// 列文件const list = await client.call('/file/list', { path: '/sdcard/Download' });console.log(list.files);</script>5.2 Node.js 端接入
const io = require('socket.io-client');const SimpleSignalClient = require('simple-signal-client');const wrtc = require('wrtc');const { RPCClient } = require('./rpc-core.js');const { FsDownloadSink, FsUploadSource } = require('./storage-node.js');const client = new RPCClient('room-android-001', 'http://dev.dtns.top', {}, { socketIo: io, SimpleSignalClient, rtcOptions: { wrtc, iceServers: [{ urls: 'turn:static.dtns.top:3478' }], },});await client.connect();// 命令console.log(await client.call('/command', { command: 'screen_info' }));// 下载await client.download( '/file/get', { path: '/sdcard/Download/test.png' }, new FsDownloadSink({ savePath: './test.png' }));// 上传await client.upload( new FsUploadSource('./test.png'), '/file/put', { path: '/sdcard/Download/' });5.3 Android 作为 Client(反向连接)
# 1. 配置信令curl "http://127.0.0.1:58082/api/?command=webrtc_set_signal&url=http://dev.dtns.top"# 2. 配置要连接的目标房间curl "http://127.0.0.1:58082/api/?command=webrtc_set_client_room&room=room-clean-demo"# 3. 启动 Clientcurl "http://127.0.0.1:58082/api/?command=webrtc_client_start"# 4. 等待连接建立sleep 5# 5. 远程调用curl "http://127.0.0.1:58082/api/?command=webrtc_rpc_call&url=/command¶ms=%7B%22command%22%3A%22screen_info%22%7D"# 6. 远程上传curl "http://127.0.0.1:58082/api/?command=webrtc_rpc_upload&url=/file/put&path=/sdcard/test.png"# 7. 远程下载curl "http://127.0.0.1:58082/api/?command=webrtc_rpc_download&url=/file/get¶ms=%7B%22path%22%3A%22/remote/test.png%22%7D&save=/sdcard/test.png"六、性能对比
6.1 HTTP vs WebRTC RPC
6.2 实测数据
- 局域网下载 83MB
HTTP 约 3-5 秒,WebRTC RPC 约 1-2 秒 - 跨省下载 83MB
HTTP 需公网 IP,WebRTC RPC 直连约 5-10 秒 - 大 JSON 500KB
HTTP 直接传,WebRTC RPC gzip 后约 30KB
注:Android WebView 由于桥接开销,速度约为 Node.js 版的 1/10,但仍比 HTTP 快(无 Base64 膨胀)。
七、兼容性说明
7.1 完全向后兼容
- HTTP API 保持不变
所有原有命令、参数、返回格式、错误码完全一致 - WebRTC 通道是新增能力
不启用时不影响任何现有功能 - 配置文件兼容
新增字段可选,无强制要求
7.2 数据格式兼容
command=home | {command: 'home'} | |
params: {...} | ||
{status:'error', message} | ||
同一份业务代码,两套 API 都能用。
7.3 文件路径兼容
/sdcard/Download/,回退 App 私有目录 | |
/sdcard/Download/,回退 App 私有目录 | |
/sdcard/ |
与 HTTP 的 file_upload / file_download 默认路径一致。
八、安全性与 E2EE
8.1 加密机制
WebRTC 强制加密,所有 DataChannel 走 DTLS-SRTP:
每个 Peer 生成自签名证书 SDP 里带 a=fingerprint(证书指纹)握手时校验指纹,防中间人 - 媒体和 DataChannel 全部加密
8.2 是否 E2EE
关键:信令服务器是信任锚。
- 信令走 HTTPS/WSS + 你自己控制的服务器
→ 达到 E2EE 级别 - 信令被第三方控制
→ 需要额外验证(如 fingerprint 外带校验)
8.3 增强建议
- 确保信令走 HTTPS/WSS
(默认配置已启用) - 用自己控制的信令服务器
(不使用公共信令) - 可选
:在 UI 上展示 fingerprint,让用户手动核对
九、部署建议
9.1 信令服务器
dev.dtns.top) | |
simple-signal-server | |
9.2 TURN 服务器
9.3 Android 权限
WebRTC RPC 需要:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><!-- 写 /sdcard/Download/ 需要 --><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />不申请 MANAGE_EXTERNAL_STORAGE 时,文件默认保存到 App 私有目录(/storage/emulated/0/Android/data/com.example.dtnsbot/files/downloads/),无需任何权限。
十、迁移指南
10.1 从 HTTP-only 迁移到 WebRTC RPC
步骤:
- 部署信令服务器
(或使用 dev.dtns.top) - Android 端配置
webrtc_set_signal+webrtc_set_server_room - 启动 Server
webrtc_server_start - 客户端引入 RPC 库
rpc-core.js+ 依赖 - 替换调用
fetch('/api/?command=...')→client.call('/command', {...})
渐进式迁移:
- 先保留 HTTP
WebRTC 作为补充 - HTTP 用于
简单命令、调试、脚本 - WebRTC 用于
大文件、跨 NAT、实时交互 - 两者可共存
不冲突
10.2 从 dtnsbot 旧版升级
升级步骤:
更新 APK(v2.0+) 无需改动 HTTP 调用代码 配置文件自动兼容 如需 WebRTC:通过 HTTP 触发 webrtc_server_start
回滚:
禁用 WebRTC: webrtc_server_stop+webrtc_client_stopHTTP API 不受影响
十一、常见问题
Q1:HTTP API 会被移除吗?
不会。HTTP API 是 dtnsbot 的核心能力,会长期保留。WebRTC RPC 是补充,不是替代。
Q2:什么时候用 HTTP,什么时候用 WebRTC?
| HTTP | |
| WebRTC | |
| WebRTC | |
| WebRTC | |
| HTTP |
Q3:WebRTC 需要 TLS 证书吗?
不需要。WebRTC 自签名证书 + DTLS 自动加密。信令服务器(Socket.IO)需要 HTTPS/WSS,但这是服务器侧的事。
Q4:文件保存到哪里?
- 优先
/sdcard/Download/<原名>(需 MANAGE_EXTERNAL_STORAGE) - 回退
/storage/emulated/0/Android/data/com.example.dtnsbot/files/downloads/<原名> - 可通过
params.path指定目标目录
Q5:WebRTC 比 HTTP 慢吗?
- 命令调用
WebRTC 略快(无 HTTP 请求开销) - 小文件
WebRTC 略快(无 Base64 膨胀) - 大文件
WebRTC 明显快(分片 + 断点续传 + 动态切片) - Android WebView
由于桥接开销,速度约为 Node 版的 1/10
Q6:安全吗?
传输加密:✅ 强制 DTLS-SRTP。 E2EE:取决于信令可信度。
用自己的信令服务器 → E2EE 级别 用公共信令 → 传输加密,但信令可 MITM
Q7:可以同时运行 Server 和 Client 吗?
可以。Android 设备可以同时作为 Server(被连接)和 Client(主动连接)。
Q8:能跨设备互联吗?
可以:
Android ↔ 浏览器 Android ↔ Node Android ↔ Android 浏览器 ↔ Node
只要它们用同一套 rpc-protocol.js + rpc-core.js。
十二、技术栈与文件清单
12.1 核心文件
rpc-protocol.js | |
rpc-core.js | |
storage-android.js | |
storage-browser.js | |
storage-node.js | |
opfs-utils.js | |
rpc-bridge.html | |
WebrtcRpcManager.kt |
12.2 依赖
socket.io-client | |
simple-signal-client | |
jszip | |
wrtc |
十三、后续计划
13.1 短期(v2.1)
- fingerprint 外带校验
UI 展示证书指纹,用户手动核对,防信令 MITM - 断点续传持久化
streamId存 OPFS,App 重启后继续 - 性能优化
Android WebView 用 WebMessagePort传 ArrayBuffer(去掉 Base64)
13.2 中期(v2.2)
- 多连接管理
一个 Android 同时连多个 Client - 文件树 API
递归列目录、目录创建 - 批量操作
批量上传/下载/删除
13.3 长期(v3.0)
- Signal Protocol 集成
信令不可信下的强 E2EE - Android Native WebRTC
替换 WebView,性能追平 Node - 信令服务器内嵌
Android 自带信令,完全自包含
十四、总结
| 命令调用 | ||
| 文件传输 | ||
| NAT 穿透 | ||
| 大文件 | ||
| 断点续传 | ||
| 进度反馈 | ||
| 大 JSON | ||
| 加密 | ||
| 兼容性 |
核心价值:
dtns.rpc-fast 的整合,让 dtnsbot 从"HTTP-only 的局域网工具"升级为"支持 NAT 穿透、大文件传输、实时交互的分布式 RPC 平台",同时保持对原有 HTTP API 的完全兼容。
附录:快速上手
# ===== Android 端 =====# 1. 配置信令curl "http://127.0.0.1:58082/api/?command=webrtc_set_signal&url=http://dev.dtns.top"# 2. 配置房间curl "http://127.0.0.1:58082/api/?command=webrtc_set_server_room&room=room-android-001"# 3. 启动 Servercurl "http://127.0.0.1:58082/api/?command=webrtc_server_start"# 4. 查看状态curl "http://127.0.0.1:58082/api/?command=webrtc_status"# ===== 浏览器端 =====# 1. 引入依赖<script src="socket.io.min.js"></script><script src="simple-signal-client.min.js"></script><script src="jszip.min.js"></script><script src="rpc-protocol.js"></script><script src="rpc-core.js"></script><script src="opfs-utils.js"></script><script src="storage-browser.js"></script># 2. 连接const client = new RPCCore.RPCClient('room-android-001', 'http://dev.dtns.top', {}, { socketIo: io, SimpleSignalClient: window.SimpleSignalClient, rtcOptions: { iceServers: [{ urls: 'turn:static.dtns.top:3478' }] }, createDownloadSink: () => new BrowserStorage.OpfsDownloadSink({ dir: 'downloads' }), wrapUploadSource: (src) => src instanceof Blob ? new BrowserStorage.FileUploadSource(src) : src,});await client.connect();# 3. 调用命令await client.call('/command', { command: 'home' });# 4. 下载文件const dl = await client.download('/file/get', { path: '/sdcard/Download/test.png' });# 5. 上传文件await client.upload(file, '/file/put', { path: '/sdcard/Download/' });文档版本:v2.0 最后更新:2026-09-18 维护者:dtnsbot 团队 相关文档:
dtnsbot-skill.md(HTTP API 主文档) skill文档:https://skills.html.dtns.top/dtnsbot-skill.html (底部带有新的webrtc通讯文档) dtns.rpc-fast技术白皮书(待发布) 体验链接:http://web3.dtns.top/dtns.rpc-fast/dtnsbot-rpc-client.html