У меня есть длительный серверный процесс внутри сеанса экрана на моем сервере Linux. Это немного нестабильно (и, к сожалению, не мое программное обеспечение, поэтому я не могу это исправить!), Поэтому я хочу создать сценарий ночного перезапуска процесса, чтобы повысить стабильность. Единственный способ заставить его выполнить корректное завершение работы - это перейти к экранному процессу, переключиться в окно, в котором он работает, и ввести строку «stop» на его консоли управления.
Могу ли я сделать какие-то умные переадресации, чтобы cronjob отправлял эту команду остановки в определенное время каждый день?
Этот ответ не решает проблему, но он оставлен здесь, потому что 30+ человек сочли его полезным., а то давно бы удалил.
Написать в /proc/*pid of the program*/fd/0
. В fd
подкаталог содержит дескрипторы всех открытых файлов и файловый дескриптор 0
- стандартный ввод (1 - стандартный вывод, а 2 - стандартный ввод).
Вы можете использовать это для вывода сообщений на tty, на котором работает программа, хотя это не позволяет вам писать в саму программу.
Терминал 1:
[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat
Терминал 2:
[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0
Запускаем сервер так:
# screen -d -m -S ServerFault tr a-z A-Z # replace with your server
экран запустится в автономном режиме, поэтому, если вы хотите увидеть, что происходит, запустите:
# screen -r ServerFault
Управляйте сервером так:
# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF
(этот ответ основан на отправка ввода текста на отдельный экран из Unix и Linux братский сайт)
Объяснение параметров:
-d -m Start screen in "detached" mode. This creates a new session but doesn't attach to it. This is useful for system startup scripts. -S sessionname When creating a new session, this option can be used to specify a meaningful name for the session. -r [pid.tty.host] -r sessionowner/[pid.tty.host] resumes a detached screen session. -p number_or_name|-|=|+ Preselect a window. This is useful when you want to reattach to a specific window or you want to send a command via the "-X" option to a specific window. -X Send the specified command to a running screen session e.g. stuff.
вещи [строка]
Stuff the string string in the input buffer of the current window. This is like the "paste" command but with much less overhead. Without a parameter, screen will prompt for a string to stuff.
Запускаем сервер так:
# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server
tmux запустится в автономном режиме, поэтому, если вы хотите увидеть, что происходит, запустите:
# tmux attach-session -t ServerFault
Управляйте сервером так:
# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF
Объяснение параметров:
new-session [-AdDP] [-c start-directory] [-F format] [-n window-name] [-s session-name] [-t target-session] [-x width] [-y height] [shell-command] Create a new session with name session-name. The new session is attached to the current terminal unless -d is given. window-name and shell-command are the name of and shell command to execute in the initial window. If -d is used, -x and -y specify the size of the initial window (80 by 24 if not given). send-keys [-lR] [-t target-pane] key ... (alias: send) Send a key or keys to a window. Each argument key is the name of the key (such as `C-a' or `npage' ) to send; if the string is not recognised as a key, it is sent as a series of characters. The -l flag disables key name lookup and sends the keys literally.
Можно отправить вводимый текст в работающий процесс без запуска screen
утилита или любая другая необычная утилита. И это можно сделать, отправив этот входной текст в стандартный входной "файл" процесса. /proc/PID#/fd/0
.
Однако вводимый текст должен быть отправлен особым образом, чтобы процесс мог его прочитать. Отправка вводимого текста через обычный файл write
не приведет к тому, что процесс получит текст. Это потому, что это только добавит к этому «файлу», но не запустит процесс для чтения байтов.
Чтобы запустить процесс чтения байтов, необходимо выполнить IOCTL
операция типа TIOCSTI
для каждого отправляемого байта. Это поместит байт в стандартную входную очередь процесса.
Это обсуждается здесь с некоторыми примерами на C, Perl и Python:
-
Итак, чтобы ответить на исходный вопрос, заданный почти 9 лет назад, задание cron должно было бы запустить небольшой служебный скрипт / программу, аналогичную примерам, которые люди написали для этого другого вопроса, которая отправит строку «stop \ n» этому серверному процессу. в вопросе, отправив каждый из 5 байтов через IOCTL
операция типа TIOCSTI
.
Конечно, это будет работать только в системах, поддерживающих TIOCSTI
IOCTL
тип операции (как в Linux), и только от root
учетной записи пользователя, поскольку эти "файлы" под /proc/
"принадлежат" root
.
Попробуйте это для начала:
# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d
И это убить:
# cd /path/to/wd
# echo "stop" > cmd
# rm cmd
Если это кому-то поможет:
У меня была аналогичная проблема, и поскольку процесс, который я использовал, не находился под screen
или tmux
, Мне пришлось использовать другой подход.
Я прикрепил gdb
к xterm
что мой процесс работал, и использовал call write(5, "stop\n", 5)
из gdb
для записи в дескриптор главного файла pty.
Я выяснил, в какой файловый дескриптор отправлять данные, посмотрев на /proc/<pid>/fd
для ссылки на /dev/ptmx
а затем методом проб и ошибок между двумя вариантами (отправка моей строки в оба совпадающих файловых дескриптора, похоже, не причинила вреда).
Оказалось, что xterm
процесс, к которому я подключился, был порожден spawn-new-terminal()
xterm
действие от привязки клавиш, а второй ptmx
дескриптор файла был просто ptmx
родителя xterm
процесс, который не был закрыт.
Следовательно, вызовы проб и ошибок отправили вывод на этот другой терминал.
Наиболее xterm
у процессов нет двух ptmx
файловые дескрипторы.
Это эффективно ввело эту строку в терминал и, следовательно, отправило ее процессу, работающему под ним.
n.b. вам может потребоваться разрешить подключение к запущенному процессу с помощью чего-то вроде
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"
Поскольку я не могу прокомментировать наиболее распространенный ответ Кристиана Чупиту (2010 г.), я должен выделить его в отдельный ответ:
Этот вопрос уже решался в этой ветке: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process
Коротко:
Вы должны начать свой процесс с канала для stdin, который не блокируется и не закрывается, когда текущий ввод был записан. Это может быть реализовано с помощью простого бесконечного цикла, который будет передан рассматриваемому процессу:
$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart
Я могу подтвердить, что это отличается от способа Крисси открыть трубу, который не работал в моем случае. Показанное решение действительно работало.
Затем вы можете записать в файл ... / fd / 0 процесса, чтобы отправить ему инструкции. Единственный недостаток заключается в том, что вам также необходимо завершить процесс bash, который выполняет бесконечный цикл после того, как сервер завершил работу.