Что означает "порт занят"?Я как-то совсем стороной обходил все что касается операционок, администрирования и девопса, хотя сказать есть что. Особенно в свете последних собеседований 🙂 Открою эту рубрику постом про занятые порты.
На моих собесах мы разворачиваем приложение и делаем что-то полезное в нем. Во время старта приложения поднимается база, веб-сервер, фронт и что-то еще по мелочи, вполне типовой набор для веб проекта. И вот тут, с вероятностью 50 на 50, падает с ошибкой:
Error: bind() to port 5432 failed: Address already in use
Что я заметил. Даже если эта строчка есть в выводе, многие ее как будто не замечают. Возможно это потому что нет понимания проблематики и человек автоматически ее игнорирует. Даже если так, то имеет смысл приучить себя после падения брать весь трейс и кидать его ии с вопросом "почему упало?". А упало потому что порт уже занят. Давайте немного теории, для понимания происходящего.
Такие штуки как базы данных, веб-серверы и любые другие серверные приложения должны уметь принимать внешние соединения. Для этого в операционных системах существует базовая концепция - сетевые сокетыю Сокет — это точка входа, через которую процесс может принимать и отправлять сетевые данные.
Когда серверное приложение стартует, оно создаёт сокет и привязывает его к конкретному порту (и ip). Этим оно сообщает операционной системе: «все соединения, пришедшие на этот порт, передавай мне». Если в этот момент порт уже занят другим процессом, операционная система не может создать второй сокет на тот же порт и возвращает ошибку
Address already in use.
С этим разобрались. Что теперь делать?
Если мы точно знаем что там запущено и нам надо чтобы работали обе программы, то нужно разносить их по разным портам. Смотрим как поменять порт и стартуем на другом. Главное потом не забыть поправить клиентов, которые будут стучаться не туда если поменять порт.
Если для нас это сюрприз, то для начала надо посмотреть, а что там вообще запущено? Есть много способов, самый простой и универсальный:
lsof -i :5432 # может понадобиться sudo
com.docke 1682 user 241u IPv6 0x6373ba4a2a38037e 0t0 TCP *:postgresql (LISTEN)
Видим, что порт держит процесс с PID 1682. Возникает логичный вопрос: просто убить его через kill? Это почти всегда неправильный ответ. В реальных системах серверные приложения обычно запущены не вручную, а как сервисы. Это означает, что процесс был стартован менеджером сервисов, может автоматически перезапускаться, и его нужно останавливать тем же способом, каким он был запущен.
Для начала имеет смысл посмотреть, как именно был запущен процесс. Это можно сделать через
ps -fp 1682. Если в команде запуска видно что-то вроде postgres, redis, nginx и так далее, то с большой вероятностью это сервис, а не разовый процесс.
На Linux такие вещи чаще всего управляются через systemd. В этом случае имеет смысл проверить статус сервиса, например
systemctl status postgresql, и остановить его корректно командой
sudo systemctl stop postgresql.
На маке серверные приложения часто ставят через Homebrew. Там можно посмотреть список сервисов командой
brew services list, а затем остановить нужный сервис через
brew services stop postgresql.
Смысл в том, что kill это аварийная мера. Она не отключает автозапуск и не меняет состояние сервиса, поэтому процесс может тут же подняться снова. Если порт занят и вы не запускали процесс вручную, почти всегда правильный путь это найти сервис и остановить его через менеджер сервисов.
У меня был собес, на котором кандидат килял процесс, пытался запустить приложение и порт снова был занят. Он довольно долго пытался повторить это пока я ему не подсказал что происходит.
p.s. Ребят нужен такой контент (лайкните если да)? Я знаю что для многих это довольно базовый уровень, но с другой стороны, немало и тех, кто с операционками на вы.
Ссылки:
Телеграм |
Youtube |
VK