使用stdin通过/ proc / {pid} / fd / 0发送命令到java -jar

我试图使用/ proc / {pid} / fd / 0发送一个命令到我的世界服务器jar,但服务器不执行命令。

要复制我正在尝试做的事情,你可以在基于Debian的机器上(也可能是其他的Linux分发版)来做这件事。

我用什么来testing这个:

  • Ubuntu 14.04
  • minecraft_server.jar (testing1.8)
  • OpenJDK运行环境(使用default-jre-headless安装)

第一个控制台

$ java -jar minecraft_server.jar nogui 

响应:[…服务器启动并等待input]

 say hi 

响应:[19:52:23] [Server thread / INFO]:[Server] hi

第二个控制台

现在,当我切换到第二个控制台,与服务器仍然在第一我写:

 echo "say hi2" >> /proc/$(pidof java)/fd/0 

一切都很好,直到我切换回第一个控制台。 我可以看到文字“说hi2”但服务器没有识别它。 我可以在第一个控制台再次写入另一个命令,就好像从第二个控制台input的文本还没有存在。

为什么是这样? 更重要的是,如何以正确的方式使用/ proc / {pid} / fd / 0将命令发送到java jar文件?

我不知道这是否是某种我不知道的Java事物,如果我在执行服务器时可以使用某个标志或某些东西,或者它是服务器JAR本身就是问题。

我知道你可以使用screen,tail -f或者某种服务器封装来实现这个function,但这不是我所追求的。 我想以某种方式发送一个使用这个方法的命令。

感谢您的时间。 如果我需要澄清一些事情,请询问。

Solutions Collecting From Web of "使用stdin通过/ proc / {pid} / fd / 0发送命令到java -jar"

这不是Java的东西。 你所尝试的是不可行的。

像这样测试它:

控制台1:

  $ cat 

当你点击“返回”时,这基本上会回应你输入的任何内容。

Console2:找到你的cat命令的进程号。 我们说这是NNN。 做:

 $ echo Something > /proc/NNN/fd/0 

切换回Console1。 你会在控制台的输出中看到“Something”,但是没有被回显。

为什么? 做

 $ ls -l /proc/NNN/fd 

你可能会明白。 所有三个描述符, stdin 0, stdout 1和stderr 2实际上都是符号链接,并且都指向同一个伪终端从站(pts)设备,它是与您的第一个终端关联的pts。

所以基本上,当你写信给它的时候,你实际上是写给控制台的输出 ,而不是输入。 如果你从这个文件中读取,你可以窃取一些本来应该进入第一个控制台的输入(你正在争抢这个输入)。 这就是字符设备的工作原理。

/ proc文件说:

/proc/[pid]/fd/

这是一个子目录,其中包含进程已打开的每个文件的一个条目,由其文件描述符命名,并且是实际文件的符号链接。 因此,0是标准输入,1个标准输出,2个标准错误,等等。

所以这些不是由进程打开的实际文件描述符。 它们只是指向文件(或在这种情况下,字符设备)的链接,其名称表明在给定进程中它们所连接的描述符。 他们的主要职责是告诉你这个进程是重定向了它的文件描述符还是打开了新的文件描述符,以及它们指向哪个资源。

但是如果你想要一个替代的方法,你可以使用fifo命名管道。

通过执行创建一个fifo:

 $ mkfifo myfifo 

运行你的java程序:

 $ java -jar minecraft_server.jar nogui < myfifo 

打开另一个控制台 写

 $ cat > myfifo 

现在开始输入东西。 切换到第一个控制台。 你会看到你的服务器执行你的命令。

尽管如此,请注意文件的结尾。 几个进程可以写入同一个fifo ,但只要最后一个关闭它,你的服务器就会在它的标准输入上收到一个EOF。

当一个进程结束时,可以避开一个命名管道被“关闭”的事实。 您可以通过将文件描述符保留在另一个进程中打开的命名管道来完成此操作。

 #! /bin/bash # tac prints a file in reverse order (tac -> cat) cmd="tac" # create fifo called pipe mkfifo pipe # open pipe on the current process's file descriptor 3 exec 3<>pipe bash -c " # child process inherits all file descriptors. So cmd must be run from a sub- # process. This allows us to close fd so cmd does not inherit fd 3, but allow fd 3 # to remain open on parent process. exec 3>&- # start your cmd and redirect the named pipe to its stdin $cmd < pipe " & # write data to pipe echo hello > pipe echo world > pipe # short wait before tidy up sleep 0.1 # done writing data, so close fd 3 on parent (this) process exec 3>&- # tac now knows it will receive no more data so it prints its data and exits # data is unbuffered, so all data is received immediately. Try `cat` instead to see. # clean up pipe rm pipe