Порты и сокеты: ss и lsof для поиска слушающего процесса

TCP-порт — число внутри сетевого namespace, а socket — объект ядра с локальным и удалённым endpoint и состоянием. Сообщение «порт занят» означает конфликт listener в той же комбинации address/port/namespace, но ещё не говорит, какое приложение правильно.

Listener и установленное соединение

Команда ss читает таблицы sockets ядра. Флаги -ltn показывают listening TCP без разрешения service names, -p добавляет процесс, если текущему пользователю разрешено его видеть.

ss -ltn
ss -ltnp
ss -tan state established

Local Address 127.0.0.1 доступен только через loopback данного namespace. 0.0.0.0 означает все IPv4 addresses, [::] — IPv6 wildcard и иногда также IPv4 через dual-stack policy. Проверяйте фактический вывод, а не делайте универсальное предположение.

Найти owner через lsof

port=8080
lsof -nP -iTCP:"$port" -sTCP:LISTEN
lsof -nP -a -p "$$" -d 0,1,2

-nP отключает DNS и преобразование номера порта в service name, делая диагностику быстрее и однозначнее. Опция -a соединяет условия AND; без неё некоторые selections объединяются шире ожидаемого.

Namespace меняет картину

Контейнер имеет собственный network namespace. ss внутри контейнера может видеть listener на 0.0.0.0:3000, а host публикует его на 127.0.0.1:8080 через NAT/proxy. Команда на host и команда в контейнере отвечают на разные вопросы. Записывайте, где именно выполнено наблюдение.

Listener доказывает только bind/listen. Приложение может не быть ready, зависнуть при обработке или отвечать HTTP 500. После ss нужен прикладной probe через curl или клиент протокола.

Ошибка и диагностика

При Address already in use не завершайте первый найденный процесс. Зафиксируйте PID/user/command, unit или container owner и ожидаемую конфигурацию порта. Проверьте IPv4 и IPv6 listeners, namespace и socket activation systemd. Если порт принадлежит правильному старому экземпляру, причина может быть в двойном запуске deployment, а kill лишь временно скрывает orchestration defect.

Практика

Найдите на своей системе один TCP listener и опишите его address scope. Сопоставьте порт процессу через ss -p или lsof, затем проверьте команду/родителя через ps. Если подходящих listeners нет, запустите временный python3 -m http.server 18080 --bind 127.0.0.1, исследуйте его и завершите по сохранённому PID.

Что важно запомнить

Источники