我有一个HttpListener
,它在指定端口上监听本地主机(即192.168.0.10/Foobar.ext)上的任何文件请求(在这种情况下,这是使用.m3u8头文件的HLS流, .ts视频文件。但该系统应适用于任何类型的文件。
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);
}
我觉得此问题与某处超时有关。但是侦听器不会达到默认的超时时间。根据{{3}},所有默认超时应为2分钟。我无法接近。而且我认为在超时情况下返回的异常应该是ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed.
,因为我想超时会处理该连接,而不是使其崩溃?那是误会吗?
请求和响应在单独的线程上完成。但是,在响应仍在进行时完成的请求会排队,并等待响应完成,然后再开始新的响应。
有没有一种方法可以获取和调试底层套接字,以找出其关闭/崩溃的原因?还是一种替代方法,可以通过localhost请求文件并响应不使用HttpListener
的文件?
一些其他信息:它适用于使用脚本运行时版本.Net 4.x等效,.Net 4.x API兼容级别和IL2CPP脚本后端的Unity应用程序(Unity 2019.1)。但是,处理请求或响应的两个类都不是从monobevahiour继承的(这在统一线程上甚至是不可能的)。为Android构建。
赏金活动已经结束,但是只要有一些有价值的信息,我都会打开一个新的fpr!
答案 0 :(得分:0)
请参阅此博客文章,其中显示了如何使用带有PushStreamContent的aspnet webapi来流式传输视频文件。
https://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/
https://www.c-sharpcorner.com/article/asynchronous-videos-live-streaming-with-asp-net-web-apis-2-0/
答案 1 :(得分:0)
这听起来像是我以前遇到的一个问题,鉴于互联网速度缓慢或不可靠的信息,我建议可能考虑使用UDP套接字而不是TCP,因为当短暂断开连接,或者如果传输过程中丢失了少量数据,请参见here。该API非常相似,请参见here。重新实现可能会比较麻烦,但是我认为它将解决您的问题。
我的另一个见解是,您尝试catch块指定它仅接受IOException,即使它正在捕获SocketException,大多数时候我只是使用通用Exception类来避免尝试确定将要发生的异常。从哪里扔。
只需更改:
catch (IOException e)
到
catch (Exception e)
IOException和SocketException都继承自Exception类,因此其余代码保持不变。这应该给您一些有关特定问题的信息。
答案 2 :(得分:-1)
那里可能有一些问题。
首先是超时情况。可能是因为您在Internet上遇到了一些问题,所以请求和响应之间的时间比指定的时间更长(我相信,如果没有,则默认设置为60秒)。
另一件事是,文件大小可能很大,无法在一个程序包响应时完全写入。但这将在任何请求中发生,不仅发生在“不良”的互联网连接时刻。
还有可能由于互联网连接不稳定,您的“服务器”检测到“客户端”已断开连接(甚至短暂断开),因此关闭了套接字。