我正在尝试使用IO.popen来放置(使用.puts方法)并从进程到其子进程获取(使用.gets方法)消息。
我没有经过实验,我有一个问题。有了以下代码,我有一个错误,因为无法在封闭的流中写入。
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'
非常感谢您的帮助。
答案 0 :(得分: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
答案 1 :(得分:0)
关闭的IO
不能再使用了。如果您打算继续使用它,则不应关闭IO
。
如果您删除了IO#close_write
,则代码仍然存在以下问题。
rdr = Thread.new { sub_process.read }
IO#read
读取直至EOF。所以在流关闭之前它永远不会终止。您在代码中提到IO#readline
,这将是更好的选择。如果popend进程永远不会发送换行符,那么使用IO#readline
程序只会挂起。
popen的另一个问题如下。 IO#popen
创建一个新流程。进程可能会被您,其他用户,内存短缺等所杀死。不要指望您的流程始终始终运行。如果该进程被终止IO#readline
将抛出EOFError
,IO#read
将返回imidiatley。您可以使用以下代码确定终止原因。
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
答案 2 :(得分:0)
使用Thread.new
的这种形式是否有帮助?
rdr = Thread.new(sub_process) {|x| x.readlines }