Tools: I replaced lsof, ss, and netstat with a single Rust binary - Analysis

Tools: I replaced lsof, ss, and netstat with a single Rust binary - Analysis

The problem

One command, everything you need

But I didn't stop there

Interactive TUI with tree view

Docker as a first-class citizen

portview doctor

SSH remote mode

How it works

Install

What's next Every developer has been here: something is hogging port 3000 and you need to find out what. On Linux you try ss -tlnp | grep 3000. On macOS it's lsof -i :3000. On Windows... good luck. Each gives different output, different flags, and none of them tell you how long the process has been running, how much memory it's eating, or whether it's a Docker container. I got tired of this. So I built portview. That's it. Every listening port, the process behind it, PID, user, uptime, memory usage, and the full command -- in a colored table. Cross-platform. ~1.3 MB single binary. Zero runtime dependencies. No parsing lsof output through awk. No remembering whether it's -tlnp or -tulpn. Just portview. A port viewer that just lists ports isn't worth writing about. Here's what makes portview different: portview watch opens a live-refreshing TUI. Navigate with j/k, press Enter to inspect a port in detail (full command, working directory, child processes, open connections), press d to kill it. Press t to toggle tree view -- it groups child processes under their parents so you can see which workers belong to which master process: portview watch --docker shows Docker containers as rows in the table. No more running docker ps in a separate terminal and cross-referencing ports. Press d on a container row to Stop, Restart, or tail Logs. This is my favorite feature. portview doctor runs five diagnostic checks on your ports: It catches: port conflicts (two processes fighting over the same port), databases exposed on all interfaces, Docker port collisions with host processes, TIME_WAIT/CLOSE_WAIT pileups, and memory hogs. Use portview doctor --json with exit code 1 on errors for CI. It shells out to your system ssh binary (inherits your config, keys, ProxyJump, everything), runs portview --json on the remote host, and renders the output locally. Kill actions in the remote TUI are forwarded over SSH. No agents, no daemons, no new ports to open. No shelling out to lsof or ss. portview reads directly from the OS: This is why it's fast -- there's no subprocess overhead. Or grab a binary from the releases page. The codebase is ~6K lines of Rust. MIT licensed. Contributions welcome. If you've ever been frustrated by lsof, give it a try and let me know what you think: github.com/Mapika/portview Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

PORT PROTO PID USER PROCESS UPTIME MEM COMMAND 3000 TCP 48291 mark node 3h 12m 248 MB next dev 5432 TCP 1203 pg postgres 14d 2h 38 MB /usr/lib/postgresql/16/bin/postgres 6379 TCP 1198 redis redis 14d 2h 12 MB redis-server *:6379 8080 TCP 51002 mark python3 22m 45 MB uvicorn main:app --port 8080 PORT PROTO PID USER PROCESS UPTIME MEM COMMAND 3000 TCP 48291 mark node 3h 12m 248 MB next dev 5432 TCP 1203 pg postgres 14d 2h 38 MB /usr/lib/postgresql/16/bin/postgres 6379 TCP 1198 redis redis 14d 2h 12 MB redis-server *:6379 8080 TCP 51002 mark python3 22m 45 MB uvicorn main:app --port 8080 PORT PROTO PID USER PROCESS UPTIME MEM COMMAND 3000 TCP 48291 mark node 3h 12m 248 MB next dev 5432 TCP 1203 pg postgres 14d 2h 38 MB /usr/lib/postgresql/16/bin/postgres 6379 TCP 1198 redis redis 14d 2h 12 MB redis-server *:6379 8080 TCP 51002 mark python3 22m 45 MB uvicorn main:app --port 8080 PROCESS node ├── node (worker) ├── node (worker) └── node (worker) postgres └── postgres: autovacuum PROCESS node ├── node (worker) ├── node (worker) └── node (worker) postgres └── postgres: autovacuum PROCESS node ├── node (worker) ├── node (worker) └── node (worker) postgres └── postgres: autovacuum $ portview doctor ✓ No port conflicts ✗ postgres is listening on 0.0.0.0:5432 -- consider binding to 127.0.0.1 ✓ No Docker-host conflicts ✓ No stale connections ✓ No high-resource listeners $ portview doctor ✓ No port conflicts ✗ postgres is listening on 0.0.0.0:5432 -- consider binding to 127.0.0.1 ✓ No Docker-host conflicts ✓ No stale connections ✓ No high-resource listeners $ portview doctor ✓ No port conflicts ✗ postgres is listening on 0.0.0.0:5432 -- consider binding to 127.0.0.1 ✓ No Docker-host conflicts ✓ No stale connections ✓ No high-resource listeners portview ssh user@server # scan remote ports portview ssh user@server watch # full remote TUI portview ssh user@server doctor # remote diagnostics portview ssh user@server # scan remote ports portview ssh user@server watch # full remote TUI portview ssh user@server doctor # remote diagnostics portview ssh user@server # scan remote ports portview ssh user@server watch # full remote TUI portview ssh user@server doctor # remote diagnostics curl -fsSL https://raw.githubusercontent.com/mapika/portview/main/install.sh | sh # Linux/macOS brew install mapika/tap/portview # Homebrew cargo install portview # Cargo curl -fsSL https://raw.githubusercontent.com/mapika/portview/main/install.sh | sh # Linux/macOS brew install mapika/tap/portview # Homebrew cargo install portview # Cargo curl -fsSL https://raw.githubusercontent.com/mapika/portview/main/install.sh | sh # Linux/macOS brew install mapika/tap/portview # Homebrew cargo install portview # Cargo - Linux: Parses /proc/net/tcp, maps inodes to PIDs via /proc/*/fd/, reads process metadata from /proc/<pid>/status and /proc/<pid>/stat - macOS: Uses libproc FFI (proc_listpids, proc_pidfdinfo, proc_pidinfo) - Windows: Uses iphlpapi (GetExtendedTcpTable) and kernel32 (CreateToolhelp32Snapshot, GetProcessTimes)