Терминал зависает при записи в FIFO файл

Вопрос или проблема

У меня есть программа, работающая под управлением сервиса systemd, и я хотел бы передать ей текст/команды, поэтому я попробовал сделать это с помощью FIFO файла:

файл .service

[Unit]
Description=Служба сервера Minecraft!

[Service]
EnvironmentFile=/etc/systemd/system/minecraft.env
WorkingDirectory=/srv/http/mc/mcserver/
ExecStart=/srv/http/mc/mcserver/start < /srv/http/mc/mcserver/minecraft_input
StandardOutput=append:/srv/http/mc/mcserver/mcserver.log

[Install]
WantedBy=multi-user.target

файл .socket

[Socket]
ListenFIFO=/srv/http/mc/mcserver/minecraft_input
Service=minecraft.service

[Install]
WantedBy=sockets.target

Но когда я пытаюсь записать в файл (либо с помощью echo 'stop (или что-то другое)' > minecraft_input, либо echo 'stop (или что-то другое)' | tee minecraft_input), он просто зависает без вывода, и ничего не передается. (FIFO файл создан с использованием mkfifo и имеет права 664)

Есть несколько возможных проблем. Во-первых, давайте исключим systemd как фактор. Что происходит, если вы просто запустите свою службу вручную?

В одной командной строке/окне выполните

/srv/http/mc/mcserver/start < /srv/http/mc/mcserver/minecraft_input

Затем в другом окне выполните ваши команды echo. Работает ли это, как ожидалось? Мой предположение — нет.

Существует как минимум две другие потенциальные проблемы. Во-первых, когда команда echo stop > minecraft_input завершает работу, это вызовет отправку EOF через FIFO в команду start. Это приведет к закрытию стандартного ввода команды start, что мешает ей получать больше команд. Стандартный ввод нельзя повторно открыть, пока вся служба не завершит работу и не будет перезапущена systemd.

Вы можете обойти это, используя tail -F для чтения из FIFO, повторно открывая его всякий раз, когда он закрывается, вот так:

tail -F /srv/http/mc/mcserver/minecraft_input | \ 
/srv/http/mc/mcserver/start 

Другая проблема может быть в том, что команды, которые вы отправляете, слишком короткие и задерживаются в буфере. Вы можете отключить буферизацию, дополнительно изменив вашу командную строку сервера на такую:

stdbuf -o 0 tail -f /srv/http/mc/mcserver/minecraft_input | \ 
/srv/http/mc/mcserver/start 

Это изменяет стандартный вывод из tail в режим без буферизации. С этим изменением вы должны иметь возможность успешно передавать короткие команды в ваш процесс start через FIFO.

stdbuf не является утилитой POSIX стандартов, и, возможно, по умолчанию ее нет в вашей системе. Вы обычно можете найти ее в пакете с названием что-то вроде GNU Tools.

Ответ или решение

Проблема: зависание терминала при записи в FIFO файл

Обзор проблемы

Вы столкнулись с проблемой, когда ваш сервис Minecraft, запущенный через systemd, зависает при попытке передачи команд через FIFO файл. Эта проблема может быть связана с особенностями работы FIFO, а также с тем, как ваша служебная программа обрабатывает стандартный ввод. Давайте подробнее рассмотрим возможные причины и решения.

Сначала проведем диагностику

Для начала, рекомендуется исключить ошибки, связанные с systemd. Попробуйте запустить вашу программу вручную, чтобы проверить, как она реагирует на команды.

/srv/http/mc/mcserver/start < /srv/http/mc/mcserver/minecraft_input

В другом терминале выполните команду:

echo 'stop' > /srv/http/mc/mcserver/minecraft_input

Если при этом ничего не происходит, продолжим исследовать причины.

Возможные причины зависания

  1. Закрытие стандартного ввода
    При выполнении команды echo в FIFO, после завершения этой команды будет отправлен сигнал EOF (конец файла) в стандартный ввод вашей программы. Это приведет к закрытию стандартного ввода, и вы не сможете отправлять другие команды, пока сервис не будет перезапущен.

    Решение: Вместо прямого чтения из FIFO, вы можете использовать tail -F, который будет отслеживать FIFO и восстанавливать соединение в случае его закрытия:

    tail -F /srv/http/mc/mcserver/minecraft_input | /srv/http/mc/mcserver/start
  2. Буферизация данных
    Команда echo или другие короткие команды могут задерживаться в буфере перед отправкой. Это связано с тем, что стандартный ввод может быть буферизован.

    Решение: Используйте утилиту stdbuf, чтобы отключить буферизацию:

    stdbuf -o 0 tail -f /srv/http/mc/mcserver/minecraft_input | /srv/http/mc/mcserver/start

    Это позволит обеспечить немедленную передачу команд, и ваша программа сможет обрабатывать их сразу же.

Установка stdug – buf

Стоит упомянуть, что stdbuf не является стандартной утилитой POSIX и может отсутствовать на вашей системе. Обычно она доступна в пакетах GNU. Проверьте наличие и установите её, если это необходимо.

Заключение

Работа с FIFO файлами требует внимательного подхода к обработке ввода и вывода. Использование tail -F в сочетании с stdbuf может значительно повысить стабильность и эффективность вашего сервиса Minecraft, устраняя зависания терминала. Если у вас есть дополнительные вопросы или требуется помощь в настройке, не стесняйтесь обращаться за поддержкой.

Оцените материал
Добавить комментарий

Капча загружается...