CLI AI

Which process is eating my bandwidth, without nethogs

2026-08-25

ss -tnp shows every connection together with the process holding it, and ss -ti adds per-socket byte counters. Between them you get traffic attributed to a process without installing anything — which matters on a server where you are a guest, in a container, or anywhere you don't have root to add packages.

1. Who is connected, and whose process is it

clai
$ clai show established connections with their processes→ ss -tnp 'sport = :8099 or dport = :8099'State Recv-Q Send-Q  Local Address:Port  Peer Address:Port Process                              ESTAB 0      4190912     127.0.0.1:8099     127.0.0.1:52080 users:(("python3",pid=1120102,fd=4))ESTAB 324447 0           127.0.0.1:52080    127.0.0.1:8099  users:(("curl",pid=1120130,fd=4))

The Process column gives you the name and the pid directly. A Send-Q of four megabytes on the sending side is data the application has already written and the network hasn't taken yet — a reliable sign that this socket is the one filling the pipe.

2. How many bytes went through one socket

clai
$ clai show how many bytes went over this connection→ ss -tin 'dport = :8099' | grep -oE 'bytes_sent:[0-9]+|bytes_received:[0-9]+'bytes_sent:85bytes_received:8579963

This is the part worth knowing. -i adds internal TCP statistics, which include byte counters per socket. That is "traffic per process" without nethogs, because the previous command already tied the socket to a pid.

3. Interface totals

clai
$ clai show traffic counters for the lo interface→ grep -E '^\s*lo:' /proc/net/dev | awk '{print "rx_bytes="$2, "tx_bytes="$10}'rx_bytes=581097986 tx_bytes=581097986

/proc/net/dev exists on every Linux system, containers included. These are counters since boot, so on their own they mean nothing — the meaning is in the difference between two readings.

4. Throughput over one second

clai
$ clai measure the transfer rate on lo over one second→ a=$(awk '/^ *lo:/{print $10}' /proc/net/dev); sleep 1; b=$(awk '/^ *lo:/{print $10}' /proc/net/dev); echo "$(( (b-a)/1024 )) KB/s"4764 KB/s

Two readings a second apart — that is the entire principle behind every bandwidth meter. Swap lo for eth0 or enp5s0.

5. Top processes by connection count

clai
$ clai show which processes hold the most connections→ ss -tnp | awk 'NR>1 {match($0,/"[^"]+"/); if (RSTART) print substr($0,RSTART+1,RLENGTH-2)}' | sort | uniq -c | sort -rn | head -5

Connection count is not traffic, but it's a useful first cut: a process holding a hundred sockets stands out immediately. Then check the byte counters from step 2 for your suspect.

6. Watching it move

clai
$ clai refresh the connection list every second→ watch -n1 "ss -tnp state established"

ss has no repeat mode of its own, so watch supplies one. It is the poor relation of iftop, available on every machine you'll ever log into.

Gotchas

  • Connection count is not bandwidth. One socket can pull gigabytes while a hundred idle keep-alive connections move nothing. Connections find the suspect; the byte counters from ss -ti are the evidence.
  • Without root you only see your own processes. The Process column is filled in for other users' sockets only under sudo. A blank field next to someone else's connection means "not your process", not "no process".
  • Interface counters include everything on the machine. /proc/net/dev also counts package updates, monitoring agents and neighbouring containers. For a precise answer look at the socket, not the interface.

Related questions

When is nethogs worth installing after all? When you need continuous, comfortable per-process monitoring. ss covers a one-off diagnosis; staring at it for hours is another matter.

How do I see a container's traffic? Its counters live in its own network namespace: docker exec <name> cat /proc/net/dev shows exactly that container's traffic.

How do I tell a saturated link from a slow application? A growing Send-Q at a steady rate means the application writes faster than the network drains. An empty Send-Q with low throughput points at the application or the remote end instead.

See also

CliAI builds these ss filters from a plain sentence, so you don't keep the syntax in your head. Install it in one line.