我希望通过 JSON 或使用 Ruby 的其他 RPC 样式服务公开交互式命令行程序。我找到了一些技巧来做到这一点,但是在重定向输出和输入时我遗漏了一些东西。
至少在 Linux 上的一种方法是将 stdin 和 stdout 重定向到一个文件,然后与文件读取和写入异步读取和写入该文件。在谷歌搜索后我一直在尝试的另一种方法是使用 open4。这是我到目前为止编写的代码,但在从标准输出读取几行后它就卡住了。
require "open4"
include Open4
status = popen4("./srcds_run -console -game tf +map ctf_2fort -maxplayers 6") do |pid, stdin, stdout, stderr|
puts "PID #{pid}"
lines=""
while (line=stdout.gets)
lines+=line
puts line
end
while (line=stderr.gets)
lines+=line
puts line
end
end
对此的任何帮助或一些见解将不胜感激!
I'm looking to expose an interactive command line program via JSON or another RPC style service using Ruby. I've found a couple tricks to do this, but im missing something when redirecting the output and input.
One method at least on linux is to redirect the stdin and stdout to a file then read and write to that file asynchronously with file reads and writes. Another method ive been trying after googling around was to use open4. Here is the code I wrote so far, but its getting stuck after reading a few lines from standard output.
require "open4"
include Open4
status = popen4("./srcds_run -console -game tf +map ctf_2fort -maxplayers 6") do |pid, stdin, stdout, stderr|
puts "PID #{pid}"
lines=""
while (line=stdout.gets)
lines+=line
puts line
end
while (line=stderr.gets)
lines+=line
puts line
end
end
Any help on this or some insight would be appreciated!
发布评论
评论(3)
我建议使用 Xinetd (或类似的)在某个套接字上运行命令,然后使用 ruby 网络代码。您在此处的代码中已经遇到的问题之一是您的两个 while 循环是连续的,这可能会导致问题。
What I would recommend is using Xinetd (or similar) to run the command on some socket and then using the ruby network code. One of the problems you've already run into in your code here is that your two while loops are sequential, which can cause problems.
您可以尝试的另一个技巧是在命令中将 stderr 重定向到 stdout,以便您的程序只需读取 stdout。像这样的事情:
这样做的另一个好处是您可以按照程序运行期间发生的顺序获取所有消息/错误。
Another trick you might try is to re-direct stderr to stdout in your command, so that your program only has to read the stdout. Something like this:
The other benefit of this is that you get all the messages/errors in the order they happen during the program run.
编辑
您应该考虑与AnyTerm集成。然后,您可以直接公开 AnyTerm,例如通过 Apache
mod_proxy
,或者让 Rails 控制器充当反向代理(处理身份验证/会话验证,然后回放controller.request
减去任何 cookie 到localhost:
,并作为响应发送回 AnyTerm 回复的内容。)否则,您需要使用 IO::Select 或 IO::read_noblock 了解何时可以读取数据(从网络或子进程),这样就不会死锁。另请参阅此。另请检查您的 Rails 是否在多线程环境中使用或者您的 Ruby 版本是否不受 此 IO::Select 错误。
您可以从以下几行开始:
要同时处理
stdin
,请更改为:EDIT
Your should consider integrating with AnyTerm. You can then either expose AnyTerm directly e.g. via Apache
mod_proxy
, or have your Rails controller act as the reverse proxy (handling authentication/session validation, then playing backcontroller.request
minus any cookies tolocalhost:<AnyTerm-daemon-port>
, and sending back as a response whatever AnyTerm replies with.)Otherwise, you'd need to use IO::Select or IO::read_noblock to know when data is available to be read (from either network or subprocess) so you don't deadlock. See this too. Also check that either your Rails is used in a multi-threaded environment or that your Ruby version is not affected by this IO::Select bug.
You can start with something along these lines:
To also handle
stdin
, change to: