HttpListener
,监听特定端口的本地主机上任何文件请求(例如192.168.0.10/Foobar.ext),在这种情况下,它使用.m3u8头文件和.ts视频文件作为HLS流。但该系统适用于任何类型的文件。IAsyncResult result = listener.BeginGetContext(new AsyncCallback(HttpRequestListenerCallback), listener);
result.AsyncWaitHandle.WaitOne(1);
当发出请求时,回调函数会为所请求的文件(仅限该文件)创建一个
HttpListenerContext
,并像这样提取文件名:HttpListenerContext context = listener.EndGetContext(result);
string fileName = context.Request.Url.AbsolutePath.Substring(1);
上下文被添加到名为httpContexts
的字典中,并链接到一个整数commandSequenceNumber
以跟踪请求。
如果文件名有效,则会向服务器发送请求以下载文件。文件被下载并放入名为totalBufferdata
的字节数组中。到这里,一切都工作得很完美。
现在我想将所请求的(视频)文件的字节数据写回到请求该文件的上下文(HttpListenerContext.Response
)的响应中。
为此,我使用以下代码片段(这发生在文件完全下载之后):
HttpListenerResponse response = httpContexts[commandSequenceNumber].Response; //Get the appropriate context from the dictionary
response.ContentLength64 = totalBufferdata.Count;//set the length response body
Stream responseStream = response.OutputStream; //The stream to which the repsonse needs to be written
try
{
currentContext.Response.OutputStream.Write(dataNoResponseHeader, 0, dataNoResponseHeader.Length);
}
catch (IOException e)
{
Debug.LogError("Exception in writing to response::" + e);
Debug.LogError("innerException:: " + e.InnerException);
}
currentContext.Close();//close the request and response stream
这将响应发送回请求的上下文(即192.168.0.10/Foobar.ext,通过相同的端口)。
现在这很好用,只要有快速、可靠的互联网连接。当互联网连接变慢或不稳定时,我开始收到异常:
System.IO.IOException: Unable to write data to the transport connection: The socket has been shut down. ---> System.Net.Sockets.SocketException: The socket has been shut down
内部异常为:
System.Net.Sockets.SocketException (0x80004005): The socket has been shut down
我已经查了一下0x80004005
的HResult在MSDN上的对应内容,但那只是“E_FAIL未指定的失败”,所以没有什么帮助。
我一直未能弄清楚为什么会抛出套接字关闭异常(而且为什么它会发生在本地主机上,但只有当连接质量不佳时)。我确保所有所需的数据都在totalBufferData
中,因此低网速不应影响它,因为所有数据在写入响应之前都已经下载完毕。我还确保在我的代码中没有过早关闭上下文的情况。
到目前为止,我一直未能找到获取HttpListener
底层套接字的方法。我还尝试将response.OutputStream
强制转换为NetworkStream
,并从NetworkStream获取套接字,但该强制转换无效(这让我感到困惑,因为它们都是IO流?)。考虑可能是一个关闭问题,我也尝试了:
using(Stream testStream = response.OutputStream)
{
testStream.Write(totalBufferdata.ToArray(), 0, totalBufferdata.Count);
}
我觉得这个问题与某个地方的超时有关。但是监听器没有达到默认的超时时间。根据MSDN,所有默认的超时时间应该为2分钟。但是我远远达不到这个时间。而且我认为,在超时的情况下返回的异常应该是
ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed.
,因为我想象超时会处理连接,而不是崩溃?这是误解吗?请求和响应是在不同的线程上完成的。但是,当响应仍在进行时完成请求的请求会被排队,并等待响应完成后再启动新的响应。
是否有一种方法可以获取和调试底层套接字,以找出它为什么关闭/崩溃?或者还有其他方法在本地主机上请求文件并对其进行响应,而不使用
HttpListener
?
一些额外的信息:这是一个使用脚本运行时版本为.Net 4.x等效的Unity应用程序(Unity 2019.1),具有.Net 4.x API兼容性级别和IL2CPP脚本后端。但是,处理请求或响应的类都不继承自monobevahiour(在unity中线程上甚至不可能)。构建针对Android。
赏金已经结束,但是我会为那些拥有有价值信息的人开设新的赏金!
PushStreamContent
,而且stream
本身可以正常工作,但是关闭响应的内容无法正常运行。我认为使用这种方法也不能解决这个问题。 - Remy