Ruby CGI 流音频
我想做的是使用 CGI 脚本(用 Ruby 编写)从文件系统(特别是音频)读取二进制文件并将其流式传输到浏览器。
到目前为止,这就是我所做的,
require 'config'
ENV['REQUEST_URI'] =~ /\?(.*)$/
f= $config[:mdir] + '/' + $1.url_decode
f = File.open f, 'rb'
print "Content-Type: audio/mpeg\r\n"#TODO: Make it guess mime type
print "\r\n"
#Outputs file
while blk = f.read(4096)
$stdout.puts blk
$stdout.flush
end
f.close
它并不完美,存在安全漏洞(暴露了整个文件系统..),但它只是无法正常工作。它正在读取正确的文件,据我所知,它按照应有的方式以 4k 块的形式输出。使用 Safari,如果我转到 URL,它将在音频播放器上显示一个问号。如果我使用 wget 下载它,它似乎可以工作并且大小合适,但已损坏。它开始播放得很好,然后发出噼啪声,然后停止。
我该怎么做呢?我是否需要进行 Base-64 编码,是否可以在不一次性将整个文件加载到内存中的情况下进行编码?
顺便说一句,这只会在局域网上使用,而且我想要简单的设置,所以我对专用的流媒体服务器不感兴趣。
What I want to do is use a CGI script (written in Ruby) to read a binary file off of the filesystem (audio, specifically) and stream it to the browser.
This is how I am doing that so far,
require 'config'
ENV['REQUEST_URI'] =~ /\?(.*)$/
f= $config[:mdir] + '/' + $1.url_decode
f = File.open f, 'rb'
print "Content-Type: audio/mpeg\r\n"#TODO: Make it guess mime type
print "\r\n"
#Outputs file
while blk = f.read(4096)
$stdout.puts blk
$stdout.flush
end
f.close
It's not perfect, there are security holes (exposing the whole filesystem..), but it just isn't working right. It's reading the right file, and as far as I can tell, outputting it in 4k blocks like it should. Using Safari, if I go to the URL, it will show a question mark on the audio player. If I use wget to download it, it appears to work and is about the right size, but is corrupted. It begins playing fine, then crackles, and then stops.
How should I go about doing this? Do I need to Base-64 encode, if can I do that without loading the whole file into memory in one go?
Btw, this is only going to be used over local area network, and I want easy setup, so I'm not interested in a dedicated streaming server.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以只使用 IO#print 代替 IO#puts ,但这有一些缺点。
不要在 ruby 中进行文件处理
Ruby 不擅长快速执行愚蠢的任务。使用此代码,您可能无法填满您的带宽。
没有 CGI
您想要做的就是通过 http 公开文件系统的一部分,这里有一些关于如何执行此操作的选项
使用其中任何一个,http 服务器都会为您做您想要的事情。
X-Sendfile
一些 http 服务器遵循称为 X-Sendfile 的特殊标头。如果这样做,
服务器将使用指定的文件作为正文。在lighty中,这只能通过fastcgi起作用,因此您需要一个fastcgi包装器,例如: http:// cgit.stbuehler.de/gitosis/fcgi-cgi/ 。我不知道apache和其他的。
使用 ac 扩展
C 扩展擅长快速完成愚蠢的任务。我写了一个 ac 扩展,它什么也不做,只是从一个 IO 读取并将其写入另一个 IO。使用这个 c 扩展,你可以通过 ruby 填充一个 GIGABIT Lan:git://johannes.krude.de/io2io
像这样使用它:
You could just use
IO#print
instead ofIO#puts
but this has some disadvantages.Don't do the file handling in ruby
Ruby is not good in doing stupid tasks very fast. With this code, you will probably not be able to fill your bandwith.
No CGI
All you want to do is expose a part of the filestystem via http, here are some options on how to do it
Use any of these and the http server will do for you what you want.
X-Sendfile
Some http servers honor a special header called X-Sendfile. If you do
the server will use the specified file as body. In lighty this works only through fastcgi, so you would need a fastcgi wrapper like: http://cgit.stbuehler.de/gitosis/fcgi-cgi/ . I don't know about apache and others.
Use a c extension
C extensions are good at doing stupid tasks fast. I wrote a c extension which does nothing, but reading from one IO and writing it to another IO. With this c extension you can fill a GIGABIT Lan through ruby: git://johannes.krude.de/io2io
Use it like this:
puts
用于编写“行” “文本”,因此附加换行符到您提供的任何内容它(把你的 mpeg 变成垃圾)。您需要syswrite
。puts
is for writing "lines" of "text", and therefore appends a newline to whatever you give it (turning your mpegs into garbage). You wantsyswrite
.