拓冰建站拓冰建站
首页 / 资讯中心 / 正文

web-to-app 端口管理器(Port Manager)实战解析:多运行时端口分配、冲突策略与跨进程释放机制

web-to-app 端口管理器Port Manager实战解析多运行时端口分配、冲突策略与跨进程释放机制【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-appweb-to-app 是一款完全在手机上运行的 APK 工坊生成的 PHP、Node.js、Python、Go 等运行时应用都依赖本地 HTTP 端口提供服务。本文基于官方文档 端口管理器 展开系统讲解 Port Manager 的服务列表、Kill 操作、自动刷新、端口范围与冲突策略并结合 PortManager.kt 等源码深入剖析端口分配算法、僵尸端口回收和跨 App 端口发现机制读完后可完整掌握该项目端口不泄漏、冲突可治理的设计全貌。功能定位与入口Port Manager 负责统一协调所有已生成应用所使用的本地服务器端口。入口位于主界面⋮ → Port Manager详见 更多功能入口。它同时承担两类职责运维视角查看哪些端口正在被使用、归属哪个进程、响应延迟多少治理视角为各运行时PHP/Node.js/Python/Go/本地 HTTP统一分配与回收端口避免端口泄漏。官方文档中列出的核心能力与源码实现一一对应文档功能源码位置与实现要点Service list服务列表ProcessPortScanner.kt 的scanAllPorts()聚合端口、owner、PID、URL、延迟与响应状态Kill / Kill allProcessPortScanner的killProcess(port)与killAllProcesses()底层均落到PortManager.release()Auto-refreshPortManagerScreen.kt 中autoRefresh状态驱动周期性doScan()Port rangesPortManager.getRangeStats()输出各范围已分配/总量/使用率Copy port / open界面层的快捷动作基于RunningService.urlhttp://127.0.0.1:portFilterstypeFilter与关键字过滤并通过 WtaAppPortDiscovery.kt 专门识别 WebToApp 生成的 AppStatusresponding / not responding对每个端口发起 HTTPHEAD健康检查800ms 超时记录responseTimeMs延迟端口范围按运行时划分的六段端口池文档的 Port ranges — view the configured port ranges 在源码中体现为PortManager内固定定义的枚举每段 500 个端口enum class PortRange(val start: Int, val end: Int) { LOCAL_HTTP(18000, 18499), PHP(18500, 18999), NODEJS(19000, 19499), PYTHON(19500, 19999), GO(20000, 20499), GENERAL(20500, 21000); val size: Int get() end - start 1 }摘自 PortManager.kt#L27-L36几个值得注意的设计点按运行时分段PHP、Node.js、Python、Go 各有独立段界面中服务条目会按 owner 前缀php:、nodejs:、python:、go:、localhttp:推断类型并着色显示见ProcessPortScanner.ServiceType的inferServiceType()溢出兜底分配时若目标范围已满分配器会回落到GENERAL段继续寻找空位tryClaimPort()中的第二段扫描只有两段都用尽才返回PORT_UNAVAILABLE(-1)刻意不用bind(0)源码注释明确说明端口段是按运行时精心策划并暴露给用户/配置的分配器必须保持在段内因此不能用系统随机端口。各运行时的便捷入口封装了 owner 命名规则例如allocateForPhp(projectId)的 owner 为php:projectIdreleasePhp(projectId)按 owner 批量释放fun allocateForPhp(projectId: String, preferred: Int 0, conflictPolicy: ConflictPolicy ConflictPolicy.REASSIGN) allocate(PortRange.PHP, php:$projectId, preferred, conflictPolicy) fun releasePhp(projectId: String) releaseByOwner(php:$projectId)摘自 PortManager.kt#L412-L442冲突策略AUTO_KILL 与 ALERT 的完整执行路径文档 Conflict policy 一节说明当运行时需要的端口已被占用时按已配置的策略处理。源码中ConflictPolicy共三个取值但只有两个是用户可选项enum class ConflictPolicy { REASSIGN, AUTO_KILL, ALERT; companion object { fun fromName(name: String?): ConflictPolicy { return when (name?.trim()?.uppercase()) { AUTO_KILL - AUTO_KILL ALERT - ALERT else - REASSIGN } } } }摘自 PortManager.kt#L38-L52allocate()中针对首选端口被占用的完整分支逻辑如下摘自 PortManager.kt#L95-L116 的语义整理ALERT直接返回PORT_CONFLICT(-2)不打扰现有服务由运行时侧弹窗/通知让用户自行决定。适合不想误杀其他应用服务的场景。AUTO_KILL先调用release(preferredPort)释放冲突服务触发其 stop handler 并终止关联进程再进入waitUntilAvailable()以 20ms 步长轮询、最长等待AUTO_KILL_WAIT_MS 120ms重试抢占若仍失败则回退为自动分配空闲端口。REASSIGN引擎内部回退当首选端口不可用时直接跳过它在范围内自动挑选一个空闲端口。正如文档所述这是零端口/未配置端口时引擎的内部回退并非用户可选择的策略。默认策略与用户配置入口REASSIGN是allocate()的默认参数而在用户可感知的配置层面各运行时配置项portConflictMode的默认值均为AUTO_KILL例如 ApkConfig.kt 中 Node.js、PHP、Python、Go、WordPress 等多处val portConflictMode: String AUTO_KILL运行时的接线方式一致仅当用户显式指定了端口port 0时才采用用户策略否则强制使用REASSIGN例如 GoRuntime.kt#L131-L136val conflictPolicy if (port 0) { PortManager.ConflictPolicy.fromName(portConflictMode.name) } else { PortManager.ConflictPolicy.REASSIGN } val serverPort PortManager.allocateForGo(projectId, port, conflictPolicy conflictPolicy)NodeService.kt 中同样从 Intent 读取PORT_CONFLICT_MODE缺省AUTO_KILL后再走相同分支。冲突行为的单元测试佐证PortManagerTest.kt 对三种策略各有一条直接验证reassign when preferred busy without kill首选端口被ServerSocket占用时REASSIGN返回另一个可用端口且不触碰占用方alert returns conflict when preferred busyALERT返回PORT_CONFLICT原 holder 的分配保持不变auto kill takes preferred after releasing holderAUTO_KILL先触发旧服务的 stop handlerstopped标志置真随后新 owner 成功占用同一端口release invokes stop handler and terminates processrelease()会同时回调 stop handler 并终止注册的真实子进程。这些测试以 Robolectric 运行Config(sdk [33])覆盖了文档所描述的三种策略语义与释放即终止进程的联动行为。分配与释放端口不泄漏的完整闭环文档 Notes 一节的结论是——运行时通过 Port Manager 申请端口停止时释放端口因此端口不会在应用之间泄漏。源码层面这条闭环由四层机制保证1. 写锁下的统一分配入口所有分配都经过tryClaimPort()的写锁ReentrantReadWriteLock在锁内先执行purgeStaleAllocationsLocked()再检查canClaimLocked(port)段内合法性 分配表无冲突 ServerSocket实际可绑定。源码注释特意说明allocate()入口不再重复 purge因为tryClaimPort()已在同一路径的写锁内统一完成避免每次分配多做一遍昂贵的 bind 探测。2. 僵尸端口回收双阈值purgeStaleAllocations()用两个阈值判定僵尸分配PortManager.kt#L17-L19关联进程已死且分配超过STALE_THRESHOLD_MS 30s→ 回收无关联进程非外部登记且分配超过STALE_NO_PROCESS_THRESHOLD_MS 120s、端口实际空闲 → 回收。回收时一并清理portProcesses与portStopHandlers并记录日志清理僵尸端口 port (原使用者: owner)。这意味着即使某个运行时异常退出、忘记调用release()端口最多占用一个阈值周期后也会被自动回收。3. release() 的三重联动release(port)PortManager.kt#L196-L221按序完成移除 stop handler → 回调 handler让运行时自行收尾如停止服务线程→ 优雅终止关联进程destroyGracefullyCompat150ms 超时后强制destroyForciblyCompat。releaseByOwner(owner)与releaseAll()分别支撑按项目停止与界面上的Kill all按钮。4. 跨进程/跨 App 的广播协议由于每个生成的 App 是独立进程Port Manager 还通过BroadcastReceiver暴露了进程间协议使主应用里的 Port Manager 界面能治理其他已导出 App的端口PortQueryReceiver.kt响应com.webtoapp.action.PORT_QUERY以goAsync()延长生命周期返回协议版本wta.protocolVersion、包名、PID 与分配表 JSONport/owner/range/allocatedAt/pid/alivePortReleaseReceiver.kt响应com.webtoapp.action.PORT_RELEASE支持三种 extra 组合——wta.port释放单端口、wta.owner按 owner 释放、wta.releaseAll全部释放并以resultData返回实际释放数量。主动查询侧在 WtaAppPortDiscovery.ktlistInstalledWtaApps()通过 PackageManager 扫描已装应用识别 manifest 中com.webtoapp.WTA_APP_MARKERtrue标记的 WebToApp 产物并读取WTA_PROJECT_ID/WTA_PROJECT_NAME元数据queryApp()用sendOrderedBroadcast定向投递查询withTimeoutOrNull(1500ms)兜底超时未响应的 App 标记为respondedfalse, errorMessagetimeoutreleaseRemotePort()则向目标 App 定向投递单端口释放广播同样带 1.5 秒超时。这也解释了文档 Filters 中detects WebToApp apps specifically专门识别 WebToApp 应用界面里可以单独扫描本机所有 WebToApp 生成的 App 并列出它们的端口占用。界面实现服务列表、状态与快捷操作PortManagerScreen.kt 是一个约 1000 行的 Jetpack Compose 屏幕将文档列出的功能逐一落地双 Tab 结构本机服务ProcessPortScanner.scanAllPorts与 WebToApp 应用扫描WtaAppPortDiscovery.queryAllApps自动刷新autoRefresh开关打开后由LaunchedEffect循环调用doScan()屏幕内还有一个 1 秒 tick 的produceState(nowMs)驱动运行时长uptime实时刷新状态指示isResponding来自 HTTP 健康检查ProcessPortScanner.checkPortHealth对http://127.0.0.1:port/发HEAD请求800ms 连接/读取超时状态码 100–599 均视为响应列表项同时显示responseTimeMs延迟Kill 确认单条 Kill 与 Kill all 都走WtaAlertDialog二次确认防止误杀范围统计showRangeStats展开面板渲染PortManager.getRangeStats()的六段进度条allocated/total与百分比过滤与搜索typeFilterALL/各类型加关键字query双维度过滤。小结Port Manager 是 web-to-app 多运行时架构的基础设施六段式端口池保证各运行时互不串扰AUTO_KILL/ALERT两种用户策略覆盖抢端口与先问你两类偏好REASSIGN作为零端口场景的引擎回退配合 30s/120s 双阈值僵尸回收、stop handler 联动终止以及PORT_QUERY/PORT_RELEASE广播协议实现了文档所承诺的运行时通过 Port Manager 分配并在停止时释放端口端口不会在应用之间泄漏。如需继续深入建议按序阅读 PortManager.kt、ProcessPortScanner.kt、WtaAppPortDiscovery.kt 与 PortManagerTest.kt。【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门