How it works
The explanation, with examples you can run.
Listen, then look
Start a tiny HTTP server on loopback and ask who is listening:
python3 -m http.server 8000 --bind 127.0.0.1 > /dev/null 2>&1 &sleep 1ss -ltnpcurl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/State Recv-Q Send-Q Local Address:Port Peer Address:PortProcessLISTEN 0 5 127.0.0.1:8000 0.0.0.0:* users:(("python3",pid=3713,fd=3))200-l listening, -t TCP, -n numeric, -p owning process. The socket is descriptor 3 of the Python process. Send-Q on a listening socket is its backlog, the queue of connections waiting for accept. ss -tn (without -l) lists established connections; each one is identified by four values, local and remote address and port, which is why one listening port can serve thousands of clients. Clients get a temporary "ephemeral" port from the range in /proc/sys/net/ipv4/ip_local_port_range.
Three errors and what they mean
- EADDRINUSE, "Address already in use". Something already holds that address and port.
ss -ltnp 'sport = :8000'names it. Restarted servers may also hit this while old connections sit in TIME_WAIT, which is why servers setSO_REUSEADDR. - ECONNREFUSED, "Connection refused". The host answered with a reset because nothing listens there. Wrong port, server not started, or listening on another address.
- Timeouts. No answer at all usually means a firewall, security group or routing problem dropping packets, not a missing listener.
Starting a second server on the same port shows the first:
python3 -m http.server 8000 --bind 127.0.0.1 2>&1 | tail -1OSError: [Errno 98] Address already in useWhich address you bind matters. 127.0.0.1 accepts only connections from the same machine, or the same container, since each container has its own network namespace. 0.0.0.0 (or :: for IPv6) accepts on every interface. Ports below 1024 need root or CAP_NET_BIND_SERVICE.
How a name becomes an address
grep '^hosts' /etc/nsswitch.confgrep -v '^#' /etc/resolv.confgetent hosts example.comdig +short example.com Ahosts: files dns nameserver 192.168.65.7 172.66.147.243 example.com104.20.23.154 example.com172.66.147.243104.20.23.154files dns means: check /etc/hosts first, then ask the DNS servers listed in /etc/resolv.conf (here Docker Desktop's built-in resolver). getent hosts goes through exactly this path, the same as most applications; dig and nslookup talk to DNS directly and skip /etc/hosts. On systemd machines /etc/resolv.conf often points at 127.0.0.53, the local systemd-resolved cache, and resolvectl query example.com shows what it does. Addresses you see will differ, since large sites answer with many.
On macOS
The socket calls are the same, but there is no ss: use lsof -nP -iTCP -sTCP:LISTEN or netstat -an. macOS resolves names through mDNSResponder, not /etc/nsswitch.conf; dscacheutil -q host -a name example.com follows the system path, and /etc/resolv.conf exists only for compatibility.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.