Cocoa 如何在MacRuby中执行命令、将数据馈送到其stdin并从其stdout读取数据?
我试图执行一个命令,将数据馈送到它的stdin,并从它的stdout读取数据。我尝试过使用Ruby的Open3Open3以及通过MacRuby公开的NSTask。我正在编写的程序的源代码是可用的。我用Xcode和MacRuby来做这个 以下是一些选择代码: 入口点,只允许我在两种方法之间轻松切换Cocoa 如何在MacRuby中执行命令、将数据馈送到其stdin并从其stdout读取数据?,cocoa,pipe,stdout,stdin,macruby,Cocoa,Pipe,Stdout,Stdin,Macruby,我试图执行一个命令,将数据馈送到它的stdin,并从它的stdout读取数据。我尝试过使用Ruby的Open3Open3以及通过MacRuby公开的NSTask。我正在编写的程序的源代码是可用的。我用Xcode和MacRuby来做这个 以下是一些选择代码: 入口点,只允许我在两种方法之间轻松切换 def do_gpg_cmd cmd do_gpg_cmd_nstask cmd end ruby方式,使用Open3Open3 def do_gpg_cmd_ruby cmd gpg = "
def do_gpg_cmd cmd
do_gpg_cmd_nstask cmd
end
ruby方式,使用Open3Open3
def do_gpg_cmd_ruby cmd
gpg = "#{@gpg_path} --no-tty "
cmd_output = ''
logg "executing [#{cmd}]"
Dispatch::Queue.concurrent.async do
logg "new thread starting"
Open3.popen3(gpg + cmd) do |stdin, stdout, stderr|
stdin.write input_text
stdin.close
cmd_output = stdout.read
output_text cmd_output
stdout.close
logg stderr.read
stderr.close
end
end
return cmd_output
end
在这种方法中,我正在测试的应用程序通过单击应用程序中的Sign按钮冻结,该按钮运行gpg-clearsign-localuser$key
当我终止应用程序时,Xcode会在自动出现的线程诊断中显示:
libsystem_kernel.dylib`__psynch_cvwait:
0x7fff84b390f0: movl $33554737, %eax
0x7fff84b390f5: movq %rcx, %r10
0x7fff84b390f8: syscall
0x7fff84b390fa: jae 0x7fff84b39101 ; __psynch_cvwait + 17 ; THIS LINE IS HIGHLIGHTED
0x7fff84b390fc: jmpq 0x7fff84b3a4d4 ; cerror_nocancel
0x7fff84b39101: ret
0x7fff84b39102: nop
0x7fff84b39103: nop
Cocoa方法,使用NSTask
def do_gpg_cmd_nstask cmd
Dispatch::Queue.concurrent.async do
fcmd = "--no-tty " + cmd
task = NSTask.alloc.init
task.setLaunchPath(@gpg_path)
task.setArguments(fcmd.split(" ") << nil)
task.arguments.each {|a| puts "ARG: [#{a}]" }
inpipe = NSPipe.pipe
outpipe = NSPipe.pipe
errpipe = NSPipe.pipe
task.setStandardOutput(outpipe)
task.setStandardInput(inpipe)
task.setStandardError(errpipe)
output = outpipe.fileHandleForReading
errput = errpipe.fileHandleForReading
input = inpipe.fileHandleForWriting
task.launch
input.writeData input_text.dataUsingEncoding(NSUTF8StringEncoding)
input.closeFile
outdata = output.readDataToEndOfFile
errdata = errput.readDataToEndOfFile
output.closeFile
errput.closeFile
outstring = NSString.alloc.initWithData(outdata, encoding: NSUTF8StringEncoding)
errstring = NSString.alloc.initWithData(errdata, encoding: NSUTF8StringEncoding)
output_text outstring
logg errstring
end
end
我怀疑这两种方法的问题是相互排斥的:Open3Open3问题可能与阻塞读取有关,而NSTask的问题与管道问题有关。这段代码对我有用,并打印出当前目录中的文件:
framework "Cocoa"
task = NSTask.new
task.launchPath = "/bin/ls"
task.arguments = ["-l", "-a"]
stdoutPipe = NSPipe.pipe
task.standardOutput = stdoutPipe
task.launch
data = stdoutPipe.fileHandleForReading.readDataToEndOfFile
puts NSString.alloc.initWithData data, :encoding => NSASCIIStringEncoding
现在,如果我将task.arguments=[-l,-a]替换为task.arguments=-l-a.split这段代码适用于我并打印出当前目录中的文件:
framework "Cocoa"
task = NSTask.new
task.launchPath = "/bin/ls"
task.arguments = ["-l", "-a"]
stdoutPipe = NSPipe.pipe
task.standardOutput = stdoutPipe
task.launch
data = stdoutPipe.fileHandleForReading.readDataToEndOfFile
puts NSString.alloc.initWithData data, :encoding => NSASCIIStringEncoding
现在,如果我将task.arguments=[-l,-a]替换为task.arguments=-l-a.split则问题在于管道具有缓冲区大小。当缓冲区已满时,写入命令将阻塞,直到另一端读取了一些数据,以便为新数据腾出空间 代码首先尝试将所有数据写入命令的stdin。假设该命令确实读取了一些数据,将一些输出写入stdout,然后继续从其stdin读取。如果有大量数据被输入,那么在某个时候,命令的标准输出管道的缓冲区将变满。命令会一直阻塞,直到有人从标准输出管道读取数据。但是,您的ruby代码还没有完成向stdin写入数据的工作,并且会一直这样做,直到stdin管道也满了为止。现在有一个死锁
解决方案是将数据写入stdin,同时从stdout读取数据,可以是并行的,也可以是简单的按块读取。块大小不大于管道的缓冲区大小。问题是管道具有缓冲区大小。当缓冲区已满时,写入命令将阻塞,直到另一端读取了一些数据,以便为新数据腾出空间 代码首先尝试将所有数据写入命令的stdin。假设该命令确实读取了一些数据,将一些输出写入stdout,然后继续从其stdin读取。如果有大量数据被输入,那么在某个时候,命令的标准输出管道的缓冲区将变满。命令会一直阻塞,直到有人从标准输出管道读取数据。但是,您的ruby代码还没有完成向stdin写入数据的工作,并且会一直这样做,直到stdin管道也满了为止。现在有一个死锁
解决方案是将数据写入stdin,同时从stdout读取数据,可以是并行的,也可以是简单的分块方式。块大小不大于管道的缓冲区大小。感谢您的回答。当我删除它时,我会收到一条消息,说明某些东西不在自动区域中。我进一步阅读了代码,并决定将NSStringinitWithData的编码参数切换回常规样式的hash:sym=>:key,而不是sym::key。现在,行为与完全Ruby版本相同。我点击按钮,它就挂了。我不得不被迫退出。事实上,我仍然使用Ruby版本。切换回来后,我实际上可以从命令yay获得输出!但它在读取后立即挂起。根据任务实际执行的操作,您可以尝试调用Terminateh如果程序在读取后看起来挂起,我将如何调用terminate?我在读取前将其放入,并在读取后放置5秒钟睡眠,以确保程序完成对管道的写入。没有骰子。编辑:签名操作现在通常可以工作,但输出量大得多的加密操作似乎仍然无法工作。谢谢回答。当我删除它时,我会收到一条消息,说明某些东西不在自动区域中。我进一步阅读了代码,并决定将NSStringinitWithData的编码参数切换回常规样式的hash:sym=>:key,而不是sym::key。现在,行为与完全Ruby版本相同。我点击按钮,它就挂了。我不得不被迫退出。事实上,我仍然使用Ruby版本。切换回来后,我实际上可以从命令yay获得输出!但它在读取后立即挂起。根据任务实际执行的操作,您可以尝试调用Terminateh如果程序在读取后看起来挂起,我将如何调用terminate?我在读取前将其放入,并在读取后放置5秒钟睡眠,以确保程序完成对管道的写入。没有骰子。编辑:签名操作现在通常可以工作,但加密操作的输出要大得多
t、 看来还是不行,谢谢!这让我度过了一段美好的时光,但我仍然没有完全做到这一点。我在后面。还有其他的建议吗?经过更多的研究,我似乎被阻止了,因为。谢谢!这让我度过了一段美好的时光,但我仍然没有完全做到这一点。我在后面。还有什么其他的建议吗?经过进一步的研究,我似乎对此束手无策,因为。