【发布时间】:2014-11-11 23:35:10
【问题描述】:
我已经编写了一个自定义的 HTTP 服务器,它可以正常工作,直到浏览器发出一个字节范围的请求。尝试加载视频时(似乎是针对特定大小的文件,因为这种情况并非每次都发生),浏览器会使用此标头请求视频文件:
method: GET
/media/mp4/32.mp4
Connection - keep-alive
Accept - */*
Accept-Encoding - identity;q=1/*;q=0
Accept-Language - en-us/en;q=0.8
Host - localhost:20809
Referer - ...
Range - bytes=0-
User-Agent - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.170 Safari/537.36
所以服务器发送请求的文件......然后,它立即发出这个请求:
method: GET
/media/mp4/32.mp4
Connection - keep-alive
Accept - */*
Accept-Encoding - identity;q=1/*;q=0
Accept-Language - en-us/en;q=0.8
Host - localhost:20809
Referer - ...
Range - bytes=40-3689973
User-Agent - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.170 Safari/537.36
所以我将请求的字节写入输出流,但它总是在第二个请求时出错并出现错误。当浏览器发送另一个请求时,几乎就像服务器仍在尝试发送文件一样。
由于线程退出或应用程序请求,I/O 操作已中止
这是处理范围请求的代码:
public void StartServer()
{
_server = new HttpListener();
_server.Prefixes.Add("http://localhost:" + _port.ToString() + "/");
LogWebserver("Listening...");
_server.Start();
th = new Thread(new ThreadStart(startlistener));
th.Start();
}
private void startlistener()
{
while (true)
{
////blocks until a client has connected to the server
ProcessRequest();
}
}
private void ProcessRequest()
{
var result = _server.BeginGetContext(ListenerCallback, _server);
result.AsyncWaitHandle.WaitOne();
}
private void ListenerCallback(IAsyncResult result)
{
var context = _server.EndGetContext(result);
HandleContext(context);
}
private void HandleContext(HttpListenerContext context)
{
HttpListenerRequest req = context.Request;
...stuff...
using (HttpListenerResponse resp = context.Response)
{
.... stuff....
byte[] buffer = File.ReadAllBytes(localFile);
if (mime.ToString().Contains("video") || mime.ToString().Contains("audio"))
{
resp.StatusCode = 206;
resp.StatusDescription = "Partial Content";
int startByte = -1;
int endByte = -1;
int byteRange = -1;
if (req.Headers.GetValues("Range") != null)
{
string rangeHeader = req.Headers.GetValues("Range")[0].Replace("bytes=", "");
string[] range = rangeHeader.Split('-');
startByte = int.Parse(range[0]);
if (range[1].Trim().Length > 0) int.TryParse(range[1], out endByte);
if (endByte == -1) endByte = buffer.Length;
}
else
{
startByte = 0;
endByte = buffer.Length;
}
byteRange = endByte - startByte;
resp.ContentLength64 = byteRange;
resp.Headers.Add("Accept-Ranges", "bytes");
resp.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", startByte, byteRange - 1, byteRange));
resp.Headers.Add("X-Content-Duration", "0.0");
resp.Headers.Add("Content-Duration", "0.0");
resp.OutputStream.Write(buffer, startByte, byteRange);/* this is where it gives the IO error */
resp.OutputStream.Close();
resp.Close();
}
else
{
resp.ContentLength64 = buffer.Length;
resp.OutputStream.Write(buffer, 0, buffer.Length);
resp.OutputStream.Close();
resp.Close();
}
}
}
我尝试过简单地忽略包含范围的请求,但是虽然没有抛出错误,但浏览器会抛出错误,因为没有下载视频。
如何处理这些范围请求并避免 IO 错误?
【问题讨论】:
-
你设置
Accept-Ranges,Content-Range标题了吗? -
是的,自从我发布了这个,我现在设置了 Accept-Ranges 和 Content-Range。接受范围:字节内容持续时间:0.0 内容长度:4459190 内容范围:字节 0-4459189/4459190 内容类型:视频/mp4 日期:2014 年 9 月 17 日星期三 21:38:45 GMT 服务器:Microsoft-HTTPAPI /2.0 X-Content-Duration:0.0
-
如果我没有收到此 I/O 错误并且偶尔会收到指定的网络名称不再可用,它会起作用。我认为这是一个线程问题
-
I'm thinking it's a threading problem所以你希望我们在不知道你真实代码的情况下回答:) -
好的,我已经编辑了尽可能多的代码。
标签: c# .net http http-headers