将标准输入从 tty 重定向到您的应用程序

将标准输入从 tty 重定向到您的应用程序

这篇文章的后续:Shell脚本不运行java,参数错误

我用java创建了一个程序,它读取控制台,并做出相应的反应。现在我希望这个程序不断运行,并读取输入的数据,但是这台机器只有一个条形码阅读器作为输入。当我手动运行该程序时,它可以正常工作,但我无法使其自动化。我需要这个,因为它没有键盘或显示器。当它作为服务运行时,它不接受任何输入,并且 /proc/[procid]/fd/0 始终给出拒绝的权限。

我怎样才能运行这个java程序,让它总是自动重新启动,并且能够读取条形码阅读器的输入?

条形码阅读器充当通用 104 个按钮 PC、Right-AltGr、无撰写键。

答案1

您有两种主要方法来解决这个问题。

将标准输入从 tty 重定向到您的应用程序

默认情况下,系统启动到 tty1,您可以禁用该 tty 上运行的 getty 并劫持其输入以供您使用。首先禁用系统上的getty

sudo systemctl stop [email protected]
sudo systemctl disable [email protected]

您应该从 ssh 会话或另一个 getty 执行此操作,否则您将失去登录信息。您没有提到您的系统,但是对于 systemd,这就是方法 - 如果这不适合您,请查阅您的发行版文档

现在我们需要创建一个包装器脚本,其中包含您的应用程序以重定向/dev/tty1到程序的标准输入(</dev/tty1最后):/usr/local/bin/rxtxcomm

#!/bin/bash
/usr/bin/java -Djava.library.path=/usr/lib/jni \
  -cp /usr/share/java/RXTXcomm.jar -jar '/foo/bar.jar' </dev/tty1

并使其可执行:

sudo chmod +x /usr/local/bin/rxtxcomm

然后更新您的服务文件以运行此脚本。重新启动服务,它应该将其标准输入附加到/dev/tty1.

您可以通过在另一个 tty 或 ssh 会话中运行上述命令来手动尝试,但您需要以 root 身份运行它(或更改 tty 上的权限)。请注意,使用此解决方案时,您必须位于 tty1 上才能捕获任何输入(在大多数系统上为 alt+ctrl+F1)。另外,要执行此操作,您必须是 root(默认情况下是 root)或者您运行的用户必须有权直接从 tty 读取数据。

直接读取自/dev/input/

Linux 中的几乎所有设备都可以作为/dev.键盘可用于/dev/input/.您可以修改程序以直接从这些文件中读取 - 可以像任何文件一样读取它们,但会生成二进制数据,因此输入字符需要更多工作。

这是一个简短的 java 示例,摘自这个堆栈溢出问题

// replace path with path from your system
DataInputStream in = new DataInputStream(
    new FileInputStream("/dev/input/by-id/usb-0430_0005-event-kbd"));
String map = "    abcdefghijlkmnopqrstuvwxyz                                                                                                                                                                                                                                                                ";
// sizeof(struct timeval) = 16
byte[] timeval = new byte[16];
short type, code;
int value;
while (true) {
    in.readFully(timeval);
    type = in.readShort();
    code = in.readShort();
    value = in.readInt();
    System.out.printf("%04x %04x %08x %c\n", type, code, value, 
                                             map.charAt(value>>>24));
}

此方法的优点是可以连接到特定键盘 - 因此您可以连接另一个键盘而不会干扰脚本。这对于调试系统很有用。这也意味着您无需禁用 tty 或强制使用特定 tty 即可使应用程序正常工作。但是,您仍然需要以 root 身份运行,或者更改设备的权限,以便其他用户可以直接访问它。

答案2

您可能希望在开机时启动您的程序。

如何做到这一点取决于在里面Unix 或 Linux 系统使用的程序(例如,某些系统正在使用系统其他人正在使用一些系统维尼特

如果crond在您的系统上启动,请考虑@reboot在您的定时任务(5)

我怎样才能运行这个java程序,让它总是自动重新启动,并且能够读取条形码阅读器的输入?

更好的方法是编写一个足够好的程序,不会不情愿地停止。否则,将其包装到某个 shell 脚本中,以便在失败时重新启动它。

您需要了解如何从 Linux 中查看条形码读取器。可能是一些字符设备,也许是一些终端... 看终端(4),stty(1),年龄(8),术语(3),kbd_模式(1)并阅读Tty揭秘

也可以看看

当它作为服务运行时,它不接受任何输入,并且 /proc/[procid]/fd/0 始终给出权限被拒绝。

因为在这种情况下,stdin 不是终端(或键盘,或条形码阅读器)。你也许应该重定向它。

当然,在开机时启动的程序(通过 init、systemd、crontab 等)或批处理模式(使用atorbatch或什至nohup)不具有与交互式命令行相同的执行环境(不同的文件描述符、不同的文件描述符)。环境(7)....)。您要么需要在编写这些程序时考虑到这一点,要么编写一些包装 shell 脚本来很好地设置(重定向 stdin、stdout、stderr;export-ing 一些重要变量)

附言。我建议花几天时间阅读有关 Linux 的更多信息(例如高级Linux编程,从开机到 Bash 提示符,Linux简介,理解和使用systemd,Bash 初学者指南)和操作系统(例如操作系统:三个简单的部分)在编写任何单行 Java 或某些脚本之前。

相关内容