shivswami/portchk
GitHub: shivswami/portchk
一个零依赖的跨平台本地端口注册表与扫描工具,帮助开发者在应用启动前发现并解决端口冲突。
Stars: 0 | Forks: 0
# portchk
[](https://pypi.org/project/portchk/)
[](https://pypi.org/project/portchk/)
[](https://github.com/shivswami/portchk/blob/main/LICENSE)
[](https://github.com/shivswami/portchk/actions/workflows/test.yml)
**本地开发端口注册表 + 扫描器。按项目声明端口,在应用绑定失败之前检测冲突。**
如果你在本地运行多个项目,你就会知道那种痛苦:一切都默认使用 `3000` 或 `8000`,然后其中两个发生了冲突。`portchk` 维护了一个轻量级的注册表,记录哪个项目声明了哪个端口,并将其与实际正在监听的内容进行核对,这样你就能在应用拒绝启动*之前*发现冲突。
- **跨平台**:macOS/Linux 通过 `lsof`,Windows 通过 `netstat` + `tasklist`
- **零依赖**:仅使用 Python 3.8+ 标准库
- **默认安全**:在杀死进程前提示确认;在你明确采取行动之前保持只读
- **单一 JSON 注册表**:`~/.config/portchk/registry.json`(按机器划分)
## 安装
```
pip install portchk
```
使用 [uv](https://docs.astral.sh/uv/):
```
uv tool install portchk # global CLI in an isolated env (recommended)
uv pip install portchk # inside a project venv
uvx portchk # run without installing
```
或从源码安装:
```
git clone https://github.com/shivswami/portchk.git
cd portchk
pip install .
```
## 快速开始
```
portchk # show live listeners + registry status
portchk add 3000 myapp # claim port 3000 for "myapp" (uses cwd)
portchk add 8000 backend -p ~/projects/api
portchk # now shows CLAIMED / CLASH / unregistered
portchk next 3000 # find the next free port >= 3000
```
## 命令
| 命令 | 描述 |
|---|---|
| `portchk` | 默认:显示实时监听端口及注册表状态 |
| `portchk list` | 显示所有已注册的项目及其端口 |
| `portchk conflicts` | 仅显示被多个项目声明的端口 |
| `portchk next [port]` | 输出大于或等于 `port` 的下一个可用 TCP 端口(默认 3000) |
| `portchk add ` | 为项目声明一个端口(路径 = 当前目录) |
| `portchk add -p /path` | 使用显式项目路径进行声明 |
| `portchk rm ` | 释放声明 |
| `portchk kill [--force]` | 杀死正在监听某端口的进程 |
| `portchk isfree ` | 如果空闲则退出码为 0,如果被占用则退出码为 1(用于脚本编写) |
| `portchk wait [--timeout N]` | 阻塞直到端口空闲(默认 30 秒) |
| `portchk export [env\|dotenv\|json]` | 将注册表导出为环境变量、dotenv 或 JSON |
| `portchk --version` | 打印版本号 |
| `portchk --help` | 显示用法 |
## 状态输出说明
运行 `portchk` 会显示每个正在监听的 TCP 端口及其与你的注册表的关系:
- `claimed:myapp`(绿色)—— 端口处于活动状态,且其进程的 cwd 与已注册的项目路径匹配
- `claimed:myapp`(青色)—— 端口已注册,但无法确认其 cwd(Windows 或系统进程)
- `CLASH (claimed by ...)`(黄色)—— 端口处于活动状态,但正在运行的进程与已注册的项目不匹配
- `unregistered`(灰色)—— 端口正在被使用,但不在你的注册表中
## 杀死进程
当你发现冲突时,直接杀死违规进程:
```
portchk kill 3000 # prompts for confirmation
portchk kill 3000 --force # skip prompt, SIGKILL on Unix / taskkill /F on Windows
```
如果不加 `--force`,系统会要求你确认。该命令会杀死监听该端口的任何进程,无论它是否在你的注册表中。
## 使用 isfree 和 wait 编写脚本
`isfree` 和 `wait` 专为 CI、Makefile 和 shell 脚本设计。它们使用退出码而不是文本字符串来传递状态信号:
```
# 仅在端口空闲时启动 dev server
portchk isfree 3000 && npm run dev
# 条件逻辑
if portchk isfree 5432; then
echo "starting database..."
fi
# 在 CI 中:teardown 后等待端口释放
docker-compose down
portchk wait 5432 --timeout 60
pytest
```
如果端口空闲,`isfree` 的退出码为 0,如果被占用则退出码为 1。`wait` 每 0.5 秒轮询一次,当端口空闲时退出码为 0,或者超时后退出码为 1。
## 导出注册表
导出已注册的端口,以便在 docker-compose、Makefile 或 .env 文件中使用:
```
portchk export env # MYAPP_PORT=3000 / BACKEND_PORT_1=8000 / BACKEND_PORT_2=8001
portchk export dotenv # same format, alias
portchk export json # raw registry JSON
```
接入 docker-compose:
```
portchk export dotenv > .env
docker-compose up
```
变量命名:单端口项目使用 `NAME_PORT`,多端口项目使用 `NAME_PORT_1`、`NAME_PORT_2`。项目名称中的连字符和空格将转换为下划线。
## 为什么不只使用一个 markdown 文件?
当你忘记更新 markdown 列表的那一天,它就已经失效了;它既不能被查询,也无法在你的应用绑定失败之前标记冲突。`portchk` 为你提供了一个可查询的注册表(`portchk next`)和一次实时扫描,能显示机器的实际状态。
## 为什么不使用后台服务?
端口管理器不应该占用它自己的端口。`portchk` 按需运行并退出。没有 daemon,没有后台进程,也没有额外的监听 socket。
## 注册表格式
`~/.config/portchk/registry.json`:
```
{
"projects": {
"myapp": {
"ports": [3000],
"path": "/Users/you/projects/myapp"
},
"backend": {
"ports": [8000, 8001],
"path": "/Users/you/projects/api"
}
}
}
```
注册表是按机器划分的(不同机器上的端口有所不同),因此请不要同步它。
## Windows 说明
在 macOS/Linux 上,`portchk` 可以读取每个进程的工作目录,因此它可以确认注册端口上的进程是否真的是*你的*项目(绿色的 `claimed:`)。Windows 在没有提升权限的情况下不暴露进程的 cwd,因此在 Windows 上,状态回退为仅匹配端口号。冲突仍然会被检测到;cwd 确认功能会优雅降级。
## 环境要求
- **Python 3.8+**
- **macOS / Linux**:`lsof`(macOS 上预装,所有主流 Linux 发行版上均可用)
- **Windows**:`netstat` 和 `tasklist`(两者均为 Windows 内置)
没有其他依赖。`portchk` 仅使用 Python 标准库。
## 许可证
MIT —— 详见 [LICENSE](LICENSE)。
版权所有 (c) 2026 Shivprakash Swami。
标签:Python, SOC Prime, 开发工具, 无后门, 本地开发, 端口管理, 逆向工具