【发布时间】:2013-07-26 22:41:49
【问题描述】:
我有一个从$stdin 读取数据并对数据进行一些处理的应用程序。我想放入一个信号处理程序来捕获 SIGINT/SIGTERM 并正常关闭(意味着完成数据处理并在完成后退出)。棘手的部分是我希望它停止从 STDIN 读取但能够处理任何缓冲数据。这样可以启动另一个应用程序并通过相同的 STDIN 管道并从前一个应用程序停止的地方继续处理。
问题是,如果我关闭 STDIN,缓冲的内容都会丢失,或者至少无法访问。
基本上我正在尝试这个:
#!/usr/bin/ruby
Signal.trap('INT') do
$stdin.close
end
f = File.open('/tmp/out', 'a')
while (data = $stdin.read(4096)) != "" do
f.write(data)
end
它立即在$stdin.read 调用上给出IOError 异常,即使我知道它读取了一些数据(strace 显示它)。
(我不需要关闭管道,我只是为了打破while 循环。如果有更优雅的方法来打破循环并获取缓冲数据,我会愉快地接受它。)
我知道这种方法适用于操作系统级别(管道缓冲区在传递给另一个应用程序时会保留),因为我可以进行以下测试并且不会丢失任何数据:
# source.rb
i = 0
loop do
puts "%08d" % (i += 1)
end
.
# reader.rb
$stdout.write($stdin.read(9))
$stdin.close
.
ruby /tmp/source.rb | while true; do ruby reader.rb; sleep 1; done
00000001
00000002
00000003
00000004
00000005
【问题讨论】:
-
您希望在关闭管道末端和打开新进程之间的这段时间内会发生什么?如果客户端在没有监听的情况下不断将数据推送到管道中怎么办?这不是管道的工作方式。如果您需要更具弹性的机制,您可能不得不改用消息队列系统。
-
@JimGarrison 它应该缓冲数据。这就是完全管道的工作方式(至少在 linux 中,我不能代表其他操作系统)。编辑:见stackoverflow.com/questions/2715324/…