我正在编写一个 Perl 脚本,它充当一个简单的 Web 服务器,通过 HTML5 提供音频文件。我已经成功地让它向带有 HTML5 音频元素的 Web 浏览器显示页面。当浏览器通过 GET 请求请求音频文件时,它会继续侦听套接字;本例中的 hh.ogg 并尝试使用消息正文中的 ogg 进行响应。它在端口 8888 上工作。
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
my $port = 8888;
my $server = new IO::Socket::INET( Proto => 'tcp',
LocalPort => $port,
Listen => SOMAXCONN,
ReuseAddr => 1)
or die "Unable to create server socket";
# Server loop
while(my $client = $server->accept())
{
my $client_info;
my $faviconRequest = 0;
while(<$client>)
{
last if /^\r\n$/;
$faviconRequest = 1 if ($_ =~ m/favicon/is);
print "\n$_" if ($_ =~ m/GET/is);
$client_info .= $_;
}
if ($faviconRequest == 1)
{
#Ignore favicon requests for now
print "Favicon request, ignoring and closing client";
close($client);
}
incoming($client, $client_info) if ($faviconRequest == 0);
}
sub incoming
{
print "\n=== Incoming Request:\n";
my $client = shift;
print $client &buildResponse($client, shift);
print "Closing \$client";
close($client);
}
sub buildResponse
{
my $client = shift;
my $client_info = shift;
my $re1='.*?';
my $re2='(hh\\.ogg)';
my $re=$re1.$re2;
print "client info is $client_info";
# Send the file over socket if it's the ogg the browser wants.
return sendFile($client) if ($client_info =~ m/$re/is);
my $r = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n
<html>
<head>
<title>Hello!</title>
</head>
<body>
Hello World.
<audio src=\"hh.ogg\" controls=\"controls\" preload=\"none\"></audio>
</body>
</html>";
return $r;
}
sub sendFile
{
print "\n>>>>>>>>>>>>>>>>>>>>>>> sendFile";
my $client = shift;
open my $fh, '<' , 'hh.ogg';
my $size = -s $fh;
print "\nsize: $size";
print $client "Allow: GET\015\012";
print $client "Accept-Ranges: none\015\012";
print $client "Content-Type: \"audio/ogg\"\015\012";
print $client "Content-Length: $size\015\012";
print "\nsent headers before sending file";
############################################
#Take the filehandle and send it over the socket.
my $scalar = do {local $/; <$fh>};
my $offset = 0;
while(1)
{
print "\nsyswriting to socket. Offset: $offset";
$offset += syswrite($client, $scalar, $size, $offset);
last if ($offset >= $size);
}
print "Finished writing to socket.";
close $fh;
return "";
}
当 GET 请求与 hh.ogg 的正则表达式匹配时,将调用 sendFile 子例程。在关闭之前将 ogg 写入套接字之前,我在响应中发送了一些标头。这段代码的工作方式与我在 Firefox 中所期望的完全一样。当我按下播放键时,脚本从 Firefox 接收到 GET 请求 ogg,我将其发送过来,Firefox 播放该曲目。
我的问题是 Google Chrome 中的脚本崩溃了。Chrome 的开发者工具只是说它无法检索 hh.ogg。当我在脚本运行时在浏览器中访问 127.0.0.1:8888 时,我可以下载 hh.ogg。我注意到 Chrome 会对 hh.ogg 发出多个 GET 请求,而 Firefox 只会发出一个。我读过它可能出于缓存原因这样做?这可能是脚本崩溃的原因。
我有
print $client "Accept-Ranges: none\015\012";
试图阻止这种行为,但没有奏效。
我不确定要响应 Chrome 的确切标头以使其在一个 HTTP 响应中接收文件。当脚本崩溃时,我偶尔也会从 Perl 打印出这条消息;否则没有其他错误。它会在我 syswrite() 到套接字的 while 循环内的某个地方退出。
Use of uninitialized value in addition (+) at ./test.pl line 91, <$fh> line 1.
这是指这条线。
$offset += syswrite($client, $scalar, $size, $offset);
我不知道为什么会有任何未初始化的值。
有人知道为什么会发生这种情况吗?如果可能的话,我想在不需要 CPAN 的其他模块的情况下完成此操作。