2

プロセスからサブプロセスにメッセージを(.putsメソッドを使用して)配置し、(。getsメソッドを使用して)取得するためにIO.popenを使用しようとしています。

私はあまり実験されておらず、質問があります。次のコードがありますが、クローズドストリームに書き込むことができないため、エラーが発生します。

class Interface
  def initialize(path)
    @sub_process = IO.popen(path, 'w+')
  end

  def start!
    if ok?
      @sub_process.puts 'Hello', 'my name is ...'
      # and more...
    end
  end

  protected

  def ok?
    is_ready?(@sub_process) && is_cool?(@sub_process)
  end

  def is_ready?(sub_process)
    reply = process_command(sub_process, 'are u ready?')
    reply.chomp.match(/yes_i_am_ready$/)
  end

  def is_cool?(sub_process)
    reply = process_command(sub_process, 'are u cool?')
    reply.chomp.match(/yes_i_am_cool$/)
  end

  def process_command(sub_process, command)
    rdr = Thread.new { sub_process.read } # alternative: io.readlines
    sub_process.puts "#{command}"
    sub_process.close_write
    rdr.value # joins and fetches the result
  end
end

a = Interface.new("./program")
a.start!

(...) `write':書き込み用に開かれていません(IOError)

ご覧のとおり、このエラーはis_cool?テスト(http://ruby-doc.org/core/classes/IO.html#M002289で説明されています)。

しかし、process_commandメソッドでコメントしようとすると、次の行になります。

# sub_process.close_write

スクリプトがスリープしているようです...無限に:s

閉じた流れを再び開くことはできないと思います。また、プログラム「./program」の他のIO.popenインスタンスを作成することはできません。これは、最初に何らかのコマンド(「準備はできていますか?」や「クールですか?」など)で初期化する必要があるためです。私はそれを使用します(簡単なディスカッションのようにメッセージを送受信することによって)。

この問題を解決するために、現在のコードをどのように変更できますか?

編集:言い換えれば、私はそのような通信を確立したいと思います(与えられたプロトコルに従って):

Parent message:                Child answer:
--------------                 ------------

'are u ready?'                 'yes_i_am_ready'
'are u cool?'                  'yes_i_am_cool'
'Hello'                        'foo'
'my name is ...'               'bar'

助けてくれてありがとう。

4

3 に答える 3

2

おそらく、実用的な例があると役立つでしょう。これは、Linux上のMRI 1.8.7で動作することがテストされ、知られているものです。

bar.rb

#!/usr/bin/ruby1.8

begin
  loop do
    puts "You said: #{gets}"
    $stdout.flush
  end
rescue Errno::EPIPE
end

foo.rb

#!/usr/bin/ruby1.8

class Parent

  def initialize
    @pipe = IO.popen(CHILD_COMMAND, 'w+')
  end

  def talk(message)
    @pipe.puts(message)
    response = @pipe.gets
    if response.nil?
      $stderr.puts "Failed: #{CHILD_COMMAND}"
      exit(1)
    end
    response.chomp
  end

  private

  CHILD_COMMAND = './bar.rb'

end

parent = Parent.new
puts parent.talk('blah blah blah')
puts parent.talk('foo bar baz')

foo.rb出力

You said: blah blah blah
You said: foo bar baz
于 2010-03-02T16:37:18.917 に答える
0

クローズドIOは使用できなくなりました。IO引き続き使用する場合は、を閉じないでください。

削除してIO#close_writeも、次の行のコードに問題が残っています。

rdr = Thread.new { sub_process.read }

IO#readEOFまで読み取ります。したがって、ストリームが閉じられるまで、ストリームは終了しません。あなたはあなたのコードで言及IO#readlineしました、これはより良い選択肢でしょう。プログラムの使用IO#readlineは、popendプロセスが改行を送信しない場合にのみハングします。

popenのもう1つの問題は次のとおりです。IO#popencreateは新しいプロセスです。プロセスは、あなた、他のユーザー、メモリ不足、…によって殺される可能性があります。プロセスが常に実行されることを期待しないでください。プロセスが強制終了されると、IO#readlineがスローされEOFErrorIO#readimidiatleyが返されます。次のコードで終了理由を判別できます。

Process::wait(io.pid)
status= $?
status.class # => Process::Status
status.signaled? # killed by signal?
status.stopsig # the signal which killed it
status.exited # terminated normal
status.exitstatus # the return value
status.ki
于 2010-03-02T12:31:25.683 に答える
0

この形式の使用は役に立ちますThread.newか?

rdr = Thread.new(sub_process) {|x| x.readlines }
于 2010-03-02T17:14:05.947 に答える