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

Joe*_*oth 5 java linux bash stdin minecraft

我正在尝试使用 /proc/{pid}/fd/0 向 minecraft 服务器 jar 发送命令,但服务器不执行该命令。

要复制我正在尝试做的事情,您可以在基于 Debian 的机器(也可能是其他 Linux 发行版)上执行此操作。

我用什么来测试这个:

  • Ubuntu 14.04
  • minecraft_server.jar(使用 1.8 测试)
  • OpenJDK 运行时环境(使用 default-jre-headless 安装)

第一个控制台:

$ java -jar minecraft_server.jar nogui
Run Code Online (Sandbox Code Playgroud)

响应:[ ...服务器启动并等待输入]

say hi
Run Code Online (Sandbox Code Playgroud)

响应:[19:52:23] [服务器线程/信息]:[服务器] 嗨

第二个控制台:

现在,当我切换到第二个控制台时,服务器仍在第一个控制台中运行,我写道:

echo "say hi2" >> /proc/$(pidof java)/fd/0
Run Code Online (Sandbox Code Playgroud)

一切看起来都很好,直到我切换回第一个控制台。我可以看到文本“say hi2”,但服务器没有识别它。我可以再次在第一个控制台中编写另一个命令,就好像从第二个控制台输入的文本甚至不存在一样。

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

我不知道这是否是某种我不知道的 Java 东西,是否可以在执行服务器时使用某些标志或其他东西,或者是否是服务器 jar 本身的问题。

我知道您可以使用 screen、tail -f 或某种服务器包装器来完成此操作,但这不是我想要的。我想以某种方式使用这种方法发送命令。

Rea*_*tic 5

这不是 Java 的东西。你正在尝试的是根本不可行的。

像这样测试它:

控制台 1:

 $ cat
Run Code Online (Sandbox Code Playgroud)

一旦您点击“返回”,这基本上会回显您输入的任何内容。

Console2:查找您的cat命令的进程号。假设它是 NNN。做:

$ echo Something > /proc/NNN/fd/0
Run Code Online (Sandbox Code Playgroud)

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

为什么?做

$ ls -l /proc/NNN/fd
Run Code Online (Sandbox Code Playgroud)

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

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

/proc 的文档说:

/proc/[pid]/fd/

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

所以这些不是进程打开的实际文件描述符。它们只是指向文件(或在这种情况下,字符设备)的链接,其名称指示它们在给定进程中附加到哪个描述符。它们的主要职责是告诉您进程是否重定向了其文件描述符或打开了任何新的文件描述符,以及它们指向哪些资源。

但是,如果您想要另一种方式来执行此操作,则可以使用fifo- 命名管道。

通过执行以下操作创建一个fifo:

$ mkfifo myfifo
Run Code Online (Sandbox Code Playgroud)

运行你的java程序:

$ java -jar minecraft_server.jar nogui < myfifo
Run Code Online (Sandbox Code Playgroud)

打开另一个控制台。写

$ cat > myfifo
Run Code Online (Sandbox Code Playgroud)

现在开始打字。切换到第一个控制台。您将看到您的服务器正在执行您的命令。

不过,请注意您的文件结尾。多个进程可以写入同一个fifo,但是只要最后一个进程关闭它,您的服务器就会在其标准输入上收到一个 EOF。