0

摘要:在我的 init.d 启动脚本中使用命名管道寻找一些帮助。管道启动时不工作,我不知道如何杀死它。

我有这个启动脚本,我在 Ubuntu 10.04 x64 中使用它来启动我的世界服务器。我需要做的一件事是设置一个读取 FIFO,以便我可以将命令从 shell 传递到服务器。我制作了一个 .fifo 文件,如果我从 shell 手动启动服务器,效果很好,如下所示:

tail -f minecraft.fifo | /usr/lib/jvm/java-6-sun/bin/java -Xmx2048M -Xms2048M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=2 -XX:+AggressiveOpts -jar minecraft_server.jar &

当我将 tail -f minecraft.fifo 插入到初始化脚本中时,我正在苦苦挣扎。当我启动服务时,“tail -f minecraft.fifo”启动;但它不会像我从 shell 手动启动它时那样将命令传递给 minecraft 服务器。

另外,我不知道如何停止命名管道。到目前为止,我认为我需要保存进程的 PID,然后在停止期间终止该 PID。但我不知道如何从 $ 中获取 PID!到一个变量中,以便我可以回忆它。

说得通?当我调用它时,尾巴不起作用,我不知道如何杀死尾巴进程。

这是不包含命名管道的正常启动脚本:

#!/bin/bash
# /etc/init.d/minecraft

### BEGIN INIT INFO
# Provides:   minecraft
# Required-Start: $local_fs $remote_fs
# Required-Stop:  $local_fs $remote_fs
# Should-Start:   $network
# Should-Stop:    $network
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description:    Minecraft server
# Description:    Starts the minecraft server
### END INIT INFO

#Settings
JARFILE='minecraft_server.jar'
USERNAME="minecraft"
MCHOME='/home/minecraft'
NAMEDPIPE='minecraft.fifo'
DAEMON="/usr/lib/jvm/java-6-sun/bin/java -Xmx2048M -Xms2048M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=2 -XX:+AggressiveOpts -jar $JARFILE nogui $"

ME=`whoami`
as_user() {
  if [ $ME == $USERNAME ] ; then
    bash -c "$1"
  else
    su - $USERNAME -c "$1"
  fi
}

mc_start() {
  if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
  then
    echo "Tried to start but $JARFILE was already running!"
  else
    echo "$JARFILE was not running... starting."
    cd $MCHOME
    as_user "cd $MCHOME && screen -dmS minecraft $DAEMON"
    sleep 7
    if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
    then
      echo "$JARFILE is now running."
    else
      echo "Could not start $JARFILE."
    fi
  fi
}

mc_stop() {
        if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
        then
                echo "$JARFILE is running... stopping."
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'"
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
                sleep 10
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
                sleep 7
        else
                echo "$JARFILE was not running."
        fi
        if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
        then
                echo "$JARFILE could not be shut down... still running."
        else
                echo "$JARFILE is shut down."
        fi
}


#Start-Stop here
case "$1" in
  start)
    mc_start
    ;;
  stop)
    mc_stop
    ;;
  restart)
    mc_stop
    mc_start
    ;;
  status)
    if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
    then
      echo "$JARFILE is running."
    else
      echo "$JARFILE is not running."
    fi
    ;;

  *)
  echo "Usage: /etc/init.d/minecraft {start|stop|status|restart}"
  exit 1
  ;;
esac

exit 0

如果我这样修改 DAEMON 变量,脚本会启动它,并且可以使用 ps -ef 找到 tail -f:

DAEMON="tail -f minecraft.fifo | /usr/lib/jvm/java-6-sun/bin/java -Xmx2048M -Xms2048M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=2 -XX:+AggressiveOpts -jar $JARFILE nogui $"

但是如果我向 minecraft.fifo 回显命令,服务器不会读取它。查看 ps,似乎 tail -f minecraft.fifo 实际上是在一个单独的进程中开始的。这可能是问题所在。

注意:我使用 SCREEN 命令来调用 DAEMON,因为我需要一种方法来跳转到正在运行的服务器并向其发出命令。所以我只是 screen -r 作为用户 minecraft 然后我可以使用服务器。然而,一旦这个 fifo 工作,我将不再需要屏幕的东西。因此,如果这妨碍了它,则可以将其删除。

至于杀了它;如果我在 mc_stop 中放一个 killall tail,它就可以工作。但这会杀死所有尾巴,而且我还有其他人在奔跑,我不想杀死。到目前为止,我还没有弄清楚如何以存储 PID 的方式启动服务器,以便我可以使用 PID 进行终止。或者以唯一的进程名称开始尾部,这样我就可以在不危及其他尾部的情况下杀死它。

关于如何使用命名管道正确启动服务器的任何想法;然后如何正确阻止它?

4

3 回答 3

1

与其使用tail -f,为什么不运行一个脚本来监控 FIFO 命名管道呢?

#!/bin/bash
NAMEDPIPE="/path/to/minecraft.fifo"

STOP_NOW="no"
STOP_SIGNAL="there is no place like home"
DELAY="1s"

while [[ $STOP_NOW == "no" ]]; do
  read INCOMING_THINGS
  if [[ $STOP_SIGNAL == "$INCOMING_THINGS" ]]; then
    STOP_NOW="yes"
  else
    printf "%s\n" "$INCOMING_THINGS"
    sleep $DELAY
  fi
done < $NAMEDPIPE

exit 0

使用 进行测试scriptname.sh,如果您喜欢,请使用scriptname.sh | whatever_commands_here. 甚至nohup scriptname.sh | whatever_commands &

将信号发送there is no place like home\n到命名管道并且scriptname.sh应该优雅地结束。

(希望我没有误解你的问题。)

于 2011-05-05T06:29:55.547 回答
1

要从 shell 通过命名管道 (fifo) 向服务器发送命令,请参见此处:

重定向应用程序(java)的输入,但仍然允许 BASH 中的标准输入

如何在脚本中使用 exec 3>myfifo 并且不让 echo foo>&3 关闭管道?

于 2011-05-05T13:51:16.017 回答
0

好的,我只是面面相觑,意识到我不需要使用 fifo,因为我已经在使用 SCREEN 通过 mc_stop 将命令传递给它。(我没有写启动脚本,我只是在尝试调整它,所以对它不是很熟悉)

screen -p 0 -S minecraft -X eval 'stuff \"说服务器在 10 秒后关闭。保存地图...\"\015'"

这正是我想要使用 fifo 的目的。

所以……我的问题很愚蠢。此问题已解决。

@pepoluan; 非常感谢您的帮助。我非常感谢您的回复。我确实尝试使用该脚本并且它有效,但它也做了一些非常奇怪的事情。它成功地将命令发送到fifo。但随后它进入了一个奇怪的循环,并向服务器发送了某种空命令。服务器识别出第一个命令,然后开始回显“命令无法识别”。什么命令未被识别是个谜,因为它不在日志中,也没有显示在我的世界控制台中。但是,我将继续使用您的脚本,以便进一步了解 fifo。我试图对您的回复表示赞赏,但 stackexchange 告诉我我还没有足够高的声誉。因此,如果其他人可以为我投票给他;请。

于 2011-05-07T04:20:46.373 回答