0

JSON または Ruby を使用した別の RPC スタイル サービスを介して、対話型のコマンド ライン プログラムを公開しようとしています。これを行うためのいくつかのトリックを見つけましたが、出力と入力をリダイレクトするときに何かが欠けています。

少なくともLinuxでの1つの方法は、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

これまたはいくつかの洞察に関する助けをいただければ幸いです!

4

3 に答える 3

0

別のトリックとして、コマンドで stderr を stdout にリダイレクトして、プログラムが stdout を読み取るだけで済むようにすることもできます。このようなもの:

popen4("./srcds_run -console -game tf +map ctf_2fort -maxplayers 6 2>&1")

これの他の利点は、プログラムの実行中に発生した順序ですべてのメッセージ/エラーを取得できることです。

于 2010-02-28T06:27:32.553 に答える
0

私がお勧めするのは、Xinetd (または同様のもの) を使用してソケットでコマンドを実行し、次に ruby​​ ネットワーク コードを使用することです。ここでコードで既に遭遇した問題の 1 つは、2 つの while ループが連続しているため、問題が発生する可能性があることです。

于 2010-02-28T04:41:13.943 に答える
0

編集

AnyTermとの統合を検討する必要があります。次に、たとえば Apache を介して AnyTerm を直接公開するかmod_proxy、Rails コントローラーをリバース プロキシとして機能させることができます (認証/セッションの検証を処理し、 controller.requestCookie を除いてに再生しlocalhost:<AnyTerm-daemon-port>、AnyTerm の応答として応答として送り返します)。

class ConsoleController < ApplicationController
  # AnyTerm speaks via HTTP POST only
  def update
    # validate session
    ...
    # forward request to AnyTerm
    response = Net::HTTP.post_form(URI.parse('http://localhost:#{AnyTermPort}/', request.params))
    headers['Content-Type'] = response['Content-Type']
    render_text response.body, response.status
  end

それ以外の場合は、IO::SelectまたはIO::read_noblockを使用して、(ネットワークまたはサブプロセスから) データをいつ読み取れるかを知る必要があるため、デッドロックは発生しません。こちらご覧ください。また、Rails がマルチスレッド環境で使用されているか、 Ruby バージョンがこの IO::Select バグの影響を受けていないかを確認してください。

次の行に沿って何かを始めることができます。

status = POpen4::popen4("ping localhost") do |stdout, stderr, stdin, pid|  
  puts "PID #{pid}"  
  # our buffers 
  stdout_lines="" 
  stderr_lines=""
  begin
    loop do
      # check whether stdout, stderr or both are 
      #  ready to be read from without blocking 
      IO.select([stdout,stderr]).flatten.compact.each { |io|
        # stdout, if ready, goes to stdout_lines 
        stdout_lines += io.readpartial(1024) if io.fileno == stdout.fileno 
        # stderr, if ready, goes to stdout_lines 
        stderr_lines += io.readpartial(1024) if io.fileno == stderr.fileno 
      }
      break if stdout.closed? && stderr.closed? 
      # if we acumulated any complete lines (\n-terminated) 
      #  in either stdout/err_lines, output them now 
      stdout_lines.sub!(/.*\n/m) { puts $& ; '' } 
      stderr_lines.sub!(/.*\n/m) { puts $& ; '' } 
    end
  rescue EOFError
    puts "Done"
  end 
end 

も処理するstdinには、次のように変更します。

      IO.select([stdout,stderr],[stdin]).flatten.compact.each { |io|
        # program ready to get stdin? do we have anything for it?
        if io.fileno == stdin.fileno && <got data from client?>
          <write a small chunk from client to stdin>
        end
        # stdout, if ready, goes to stdout_lines 
于 2010-02-28T05:02:05.293 に答える