【发布时间】:2019-06-10 09:43:47
【问题描述】:
我有一个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 的字典中,并链接到一个 int 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 与 on msdn 的对应关系,但这只是“E_FAIL 未指定失败”,所以没有运气。
我一直无法弄清楚为什么它会引发套接字关闭的预期(以及为什么它发生在 localhost 部分,但仅在连接时不好)。我确保所有所需的数据都在totalBufferData 中,因此低网速不会影响这一点,因为在我将其写入响应之前所有数据都已下载。我确保我不会在我的代码中的任何地方过早关闭上下文。
到目前为止,我一直未能找到一种方法来访问HttpListener 的底层套接字。我还尝试将response.OutputStream 转换为NetworkStream,并从NetworkStream 获取套接字,但该转换无效(这让我感到困惑,因为它们都是IO 流?)。认为这可能是一个结束的问题,我也尝试过
using(Stream testStream = response.OutputStream)
{
testStream.Write(totalBufferdata.ToArray(), 0, totalBufferdata.Count);
}
我觉得这个问题与超时有关某处。但是侦听器没有达到默认超时时间。根据to MSDN,所有默认超时应为 2 分钟。我无法接近。而且我认为在超时的情况下返回的异常应该是ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed.,因为我认为超时会处理连接,而不是崩溃?是误会吗?
请求和响应在单独的线程上完成。但是,在响应仍在进行时完成的请求会排队,并等待响应完成,然后再开始新的响应。
有没有办法获取和调试底层套接字以找出它关闭/崩溃的原因?或者也许是通过 localhost 请求文件并响应不使用 HttpListener 的替代方法?
一些附加信息:它适用于使用脚本运行时版本 .Net 4.x 等效的 Unity 应用程序 (Unity 2019.1),具有 .Net 4.x api 兼容性级别和 IL2CPP 脚本后端。但是处理请求或响应的类都不是从 monobevahiour 继承的(这在统一的线程上甚至是不可能的)。为 Android 构建。
赏金已经结束,但我会为有有价值信息的人开一个新的!
【问题讨论】:
标签: c# sockets unity3d networking httplistener