本机谁在听:port_monitor 只绑 127.0.0.1:5005
痛点:本机挂着好几个服务时,
lsof -nP -iTCP -sTCP:LISTEN把地址和进程挤在一行。你要先回答「这个端口有没有人在听」。
极客解析:公开仓库 port_monitor 用 Flask 把这件事放进
http://127.0.0.1:5005。进程只绑回环地址,调试器关闭。
三步打开页面
pip install flask
python port_monitor.py
浏览器打开 http://127.0.0.1:5005。要躲开已占用的 5005,换一条命令:
PORT_MONITOR_PORT=5055 python port_monitor.py
监控名单在同目录 ports.json。页面上半部列出当前没在名单里、但本机正在听的 TCP 端口,填备注后可以补进名单。
表格里两列怎么来的
在听 / 没人听:对 127.0.0.1 做一次超时 0.5 秒的 TCP 连接。连上就是在听。
服务名来自 lsof -iTCP:<端口> -sTCP:LISTEN 的进程名。这个页面不杀进程。
上半部名单解析 lsof -nP 里 :端口 (LISTEN) 这一段。macOS 上地址在 NAME 列,例如 127.0.0.1:5055 (LISTEN),不在单独的 TCP 词上。
防火墙按钮默认不出现
POST /close 和 POST /open 在没设置 PORT_MONITOR_ALLOW_PF=1 时返回 403,正文是「防火墙改写默认关闭」。打开之后,那两条路径会往 /etc/pf.conf 追加 include,并执行 sudo pfctl -f /etc/pf.conf 和 sudo pfctl -e。看端口的时候不要开这个开关。
/logs/<端口> 会为该端口启动 sudo tcpdump。没配免密 sudo 时日志页失败,名单页还能用。
可运行演示
不启动网页也能先确认判定。把下面这段存成 listen_check.py 再跑:
import socket
def listening(port: int) -> bool:
sock = socket.socket()
sock.settimeout(0.5)
try:
sock.connect(("127.0.0.1", port))
return True
except OSError:
return False
finally:
sock.close()
print("5005", "在听" if listening(5005) else "没人听")
网页没开、5005 上也没有别的进程时,终端是:
5005 没人听
我写这篇时,这台机器的 5005 上已经有一个 Python 进程在听,同一行打出 5005 在听。以你自己的 lsof 为准。