Что такое lsof и где он работает
Название lsof расшифровывается как list open files: утилита показывает открытые файлы. В Unix-подобных системах сетевые сокеты тоже считаются файлами, поэтому lsof позволяет увидеть, какая программа открыла нужный порт. В macOS она установлена по умолчанию, а во многих дистрибутивах Linux ставится отдельным пакетом.
Главное достоинство lsof для этой задачи в единообразии: команда одинаково работает в macOS и Linux, тогда как ss есть только в Linux, а вывод netstat отличается между системами. Если вы пишете инструкцию для коллег с разными системами, lsof подойдёт всем.
Чтобы увидеть процессы других пользователей, запускайте команду с sudo. Без него утилита покажет только ваши процессы, и служба, запущенная системой, останется незамеченной. Это самая частая причина, по которой «порт занят, а lsof ничего не находит».
Для новичков полезно помнить простую формулу: сначала порт, затем процесс, затем решение. Не торопитесь завершать процесс: проверьте, что это за программа, кто её запустил и не нужна ли она другим службам. Часто достаточно просто закрыть приложение обычным образом.
Основные команды
Опишем самые полезные варианты.
| Команда | Что делает |
|---|---|
| sudo lsof -i :3000 | Процессы, использующие порт 3000 (TCP и UDP) |
| sudo lsof -i tcp:3000 | Только TCP порт 3000 |
| sudo lsof -iTCP -sTCP:LISTEN -P -n | Все слушающие TCP-порты |
| sudo lsof -i @192.0.2.5 | Соединения с указанным адресом |
| sudo lsof -i -P -n | Все сетевые сокеты без разрешения имён |
| lsof -t -i :3000 | Только номера PID |
Ключ -P отключает замену номеров портов названиями служб, ключ -n отключает поиск имён узлов. Оба нужны, чтобы вывод был быстрым и однозначным: вместо «http-alt» вы увидите 8080. Значение -sTCP:LISTEN оставляет только слушающие сокеты и отсекает установленные соединения.
Сочетание -iTCP и -sTCP:LISTEN одновременно в общем случае надёжно работает на обеих системах, а вот отдельные более экзотические комбинации могут отличаться по версиям, поэтому сверяйтесь с man lsof на своей машине.
Альтернативная запись без двоеточия: lsof -i TCP:3000 даёт тот же результат, что и lsof -i tcp:3000. Регистр протокола не важен. Если вам нужна выборка сразу по нескольким портам, можно перечислить их через запятую: lsof -i :3000,3001.
Как читать вывод
Пример (пример, адреса из блока документации):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 4312 user 23u IPv4 0x1a2b 0t0 TCP *:3000 (LISTEN) node 4312 user 27u IPv4 0x3c4d 0t0 TCP 192.0.2.10:3000->198.51.100.7:51234 (ESTABLISHED)
Смотрим на столбцы. COMMAND показывает имя программы, PID её идентификатор, USER владельца. В NAME указан адрес и порт: *:3000 значит, что программа слушает на всех интерфейсах, а запись со стрелкой описывает установленное соединение с другой стороной. Состояние в скобках: LISTEN или ESTABLISHED.
Для отдельного адреса прослушивания 127.0.0.1:3000 служба доступна только локально. Эта же разница описана на странице про ss: локальные службы не должны слушать все интерфейсы без необходимости.
Обратите внимание, что lsof выводит несколько строк на один процесс, если у него несколько открытых сокетов. Все они с одним PID, дублирования нет.
Столбец FD показывает дескриптор файла, а буква u в конце значения означает открытие на чтение и запись. Для диагностики порта этот столбец обычно не важен, но помогает понять, что сокет используется активно, а не оставлен закрытым.
Освободить порт: завершение процесса
Когда нужно остановить процесс, занявший порт, порядок такой.
- Выясните PID: sudo lsof -t -i :3000.
- Сначала попробуйте штатное завершение: kill PID. Программа получит сигнал завершения и закроет ресурсы аккуратно.
- Если процесс не реагирует, повторите с kill -9 PID, это принудительное завершение без очистки.
- Проверьте, что порт освободился: снова lsof -i :3000.
Существует короткая запись kill $(lsof -t -i :3000), но использовать её стоит осознанно: она завершит все процессы на этом порту, в том числе те, которые вы не собирались останавливать. Иногда порт удерживают несколько процессов-потомков, а иногда служба перезапускается автоматически менеджером служб, и после завершения процесс появляется вновь. Тогда останавливать нужно саму службу через менеджер, а не отдельный процесс.
В Linux альтернативой служит команда fuser 3000/tcp, которая тоже показывает PID владельца порта.
После завершения процесса дайте системе секунду-другую и повторите проверку. Иногда порт остаётся в состоянии ожидания закрытия, и повторный запуск программы сообщает о занятом порте, хотя процесса уже нет. Обычно достаточно подождать или выбрать другой порт.
Сравнение с другими инструментами и ограничения
Lsof работает медленнее ss на серверах с большим числом соединений, потому что перебирает все открытые файлы процессов. Для повседневных задач это несущественно, но при десятках тысяч сокетов лучше воспользоваться ss.
В macOS сокеты можно посмотреть и через netstat, но netstat не показывает владельцев так же удобно. В Windows используют netstat -ano, ему посвящена отдельная страница. Общий принцип везде одинаков: найти порт, определить процесс, принять решение.
Есть и ограничения безопасности. Современные версии macOS могут не показать процессы, защищённые системой, даже с sudo. Не завершайте незнакомые системные процессы. Если на своём компьютере вы нашли неожиданную службу, слушающую внешние адреса, разберитесь, что это за программа и откуда она пришла. Проверяйте порты только на собственных машинах.
Отдельная тема — приложения в контейнерах. Порт может быть проброшен в контейнер, и тогда lsof покажет процесс-прокладку самой платформы контейнеров, а не программу внутри. В таком случае смотрите список запущенных контейнеров и их проброшенные порты средствами самой платформы.