Назад | Перейти на главную страницу

Другие процессы занимают порт 80 при перезапуске Apache - почему и как решить?

У меня есть сервер CentOS 5.5, на котором запущен Apache на порту 80, а также некоторые другие приложения. Все работает нормально, пока мне по какой-то причине не понадобится перезапустить процесс httpd. Это возвращает:

sudo /etc/init.d/httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd: (98)Address already in use: make_sock: could not bind to address [::]:80
(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
Unable to open logs

Сначала я подумал, что, возможно, httpd завис и все еще работает, но это было не так. Итак, я запустил netstat, чтобы узнать, что использует порт 80:

sudo netstat -tlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 *:7203                      *:*                         LISTEN      24012/java          
tcp        0      0 localhost.localdomain:smux  *:*                         LISTEN      3547/snmpd          
tcp        0      0 *:mysql                     *:*                         LISTEN      21966/mysqld        
tcp        0      0 *:ssh                       *:*                         LISTEN      3562/sshd           
tcp        0      0 *:http                      *:*                         LISTEN      3780/python26

Оказывается, мой процесс python взял на себя прослушивание http в момент перезапуска httpd. Итак, я убил python и снова попытался запустить httpd, но столкнулся с той же ошибкой. Снова Netstat:

sudo netstat -tlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 *:7203                      *:*                         LISTEN      24012/java          
tcp        0      0 localhost.localdomain:smux  *:*                         LISTEN      3547/snmpd          
tcp        0      0 *:mysql                     *:*                         LISTEN      21966/mysqld        
tcp        0      0 *:ssh                       *:*                         LISTEN      3562/sshd           
tcp        0      0 *:http                      *:*                         LISTEN      24012/java

Теперь мой java-процесс взял на себя прослушивание http. Я убил и это, а затем смог успешно перезапустить httpd.

Но это ужасный обходной путь. Почему эти процессы python и java начнут прослушивать порт 80 сразу после перезапуска httpd? Как решить?

Два других комментария. 1) Процессы java и python запускаются apache из сценария php. Но при перезапуске apache они не должны пострадать. И 2) у меня такая же установка на двух других машинах под управлением Ubuntu, и там нет никаких проблем.

Любые идеи?

Редактировать:

Процесс Java слушает порт 7203, а процесс Python предположительно не слушает ни один порт. По какой-то причине они начинают прослушивать порт 80 при перезапуске apache. Раньше этого не было. На Ubuntu все работает нормально. По какой-то причине на моем текущем компьютере CentOS 5.5 возникает эта проблема.

Проблема может заключаться в том, как Apache запускает подпроцессы. Они могут быть порождены путем разветвления и предоставления клонированным процессам Apache возможности стать другими процессами. Каждый клон наследует все дескрипторы открытых файлов родительского процесса, включая дескриптор открытия порта TCP 80.

Netstat показывает только одно приложение, связанное с дескриптором открытого файла, в то время как три процесса оставляют дескриптор открытым.

Возможные решения вашей проблемы:

  1. Если важно, чтобы подпроцессы выполнялись во время перезапуска Apache, самым простым решением было бы запустить 3 процесса как отдельные системные службы.

  2. Если они зависят от работающего Apache, их также должна завершить команда apache stop. Этого можно добиться, отредактировав сценарий /etc/init.d/apache.

  3. Если вы вынуждены запускать их из Apache, вам нужно запускать их как настоящие «процессы-демоны»!

Я написал создателя демона для PyQt-приложения, вдохновленного http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/. Вы можете запустить этот скрипт из Apache, вызвать exec_as_daemon для каждого из ваших подпроцессов и закрыть его.

# Copyright: (c) 2011 phobie <pydaemon.phobie@safersignup.com>
# License: CC-by-sa 3.0
import os
def exec_as_daemon(s_path_cmd, l_args=[]):
    i_pid = os.fork()
    if i_pid != 0:
        # Always remember to gobble your zombie children
        os.wait()
        # Back to parent
        return
    # Detach from parent
    os.setsid()
    # Do not block any mounts
    os.chdir('/')
    # Reset file creation rights
    os.umask(0)
    i_pid = os.fork()
    if i_pid != 0:
        # Close the direct child process
        os._exit(0)
    # Get the maximum count of open file handles
    try:
        import resource
        i_fd_max = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
        if i_fd_max == resource.RLIM_INFINITY:
            i_fd_max = 1024
    except ImportError:
        i_fd_max = 1024
    # Try to close all possible file handles
    for i_cur_fd in range(0, i_fd_max):
        try:
            os.close(i_cur_fd)
        except OSError:
            pass
    # Assosiate STDIN with /dev/null
    os.open(os.devnull if hasattr(os, "devnull") else '/dev/null', os.O_RDWR)
    # STDOUT to /dev/null
    os.dup2(0, 1)
    # STDERR to /dev/null
    os.dup2(0, 2)
    l_args.insert(0, s_path_cmd)
    # Let the clone become a other process
    os.execv(s_path_cmd, l_args)

if __name__ == '__main__':
    exec_as_daemon('/usr/bin/java', ['-jar', '/usr/local/bin/apache_helper_daemon.jar'])
    exec_as_daemon('/usr/local/bin/apache_helper_daemon.py')

Вы не можете полностью завершить свой главный процесс apache, и его дочерние элементы остаются привязанными к сокетам. Вместо перезапуска запустите сервис httpd stop. Если это не удается правильно завершить, вам необходимо дополнительно изучить приложения java и python, которые вы включили через apache.

Если служба httpd stop работает некорректно, удалите приложения java и python, пока вы не сможете полностью перезапустить. Затем выясните, почему эти процессы не завершаются правильно.

Теоретически только один процесс должен прослушивать данный IP / порт. Если вам нужно, чтобы несколько приложений прослушивали один и тот же порт, вам понадобится установка типа обратного прокси, которая будет определять на основе полученного контента, какой процесс получить сообщение.

Было бы полезно знать, что делают ваши приложения Python и Java. Если они также являются серверами, которые прослушивают порт 80, они застревают в точке открытия порта 80 для прослушивания во время работы Apache, и как только вы убиваете Apache, следующий из очереди процессов проходит и открывает порт. Вам нужно будет изменить коды Python и Java, чтобы прослушивать разные порты.

Странно то, что происходит. В качестве обходного пути используйте reload вместо restart:

sudo /etc/init.d/httpd reload

Попробуйте узнать о новом процессе java и python. Вы можете попробовать узнать, когда они запустились, и параметры командной строки:

ps -edf|egrep 'python|java|PID'

Также проверьте /etc/init.d/httpd на все, что связано с java или python.

Используйте инструмент аудита, чтобы узнать, когда программа запущена, кем и т. Д .: