我有一个HttpListener
,它监听指定端口上localhost(即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
我已经查看了qazxsw poi的HResult与qazxsw poi相关的内容,但这只是“E_FAIL未指定的失败”,所以那里没有运气。
我一直无法弄清楚为什么它会抛出关闭套接字的预期(以及为什么它发生在localhost部分,但只有在连接不好时)。我确保所需的所有数据都在0x80004005
中,因此低互联网速度不应影响这一点,因为所有数据在我将其写入响应之前已经下载。我确保我不会在我的代码中的任何地方过早地关闭上下文。
到目前为止,我一直没有找到一种方法来到达on msdn的底层插座。我也尝试将totalBufferData
转换为HttpListener
,并从NetworkStream获取套接字,但该转换无效(这使我感到困惑,因为它们都是IO流?)。认为这可能是一个关闭问题我也尝试过
response.OutputStream
我觉得这个问题与某个地方的超时有关。但是监听器没有达到默认的超时时间。根据NetworkStream
,所有默认超时应为2分钟。我无处可去。而且我认为在超时的情况下返回的异常应该是using(Stream testStream = response.OutputStream)
{
testStream.Write(totalBufferdata.ToArray(), 0, totalBufferdata.Count);
}
,因为我认为超时会处理连接,而不是崩溃吗?这是误会吗?
请求和响应是在单独的线程上完成的。但是,在响应仍在进行时完成的请求将排队等待,并在响应开始新响应之前等待响应完成。
有没有办法获取和调试底层套接字,以找出它关闭/崩溃的原因?或者可能是通过localhost请求文件的替代方法,并回应不使用to MSDN的文件?
一些附加信息:它适用于使用脚本运行时版本.Net 4.x等效的Unity应用程序(Unity 2019.1),具有.Net 4.x api兼容级别和IL2CPP脚本后端。但处理请求或响应的类都没有继承自monobevahiour(在统一线程中甚至不可能)。为Android构建。
赏金已经结束,但我会为有任何有价值信息的人开一个新的!
请参阅此博客文章,了解如何使用带有ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed.
的aspnet webapi来传输视频文件。
HttpListener
这听起来像是我之前遇到过的一个问题,由于互联网速度慢或不可靠,我建议可能要使用UDP套接字而不是TCP,因为它们在连接被切断时不会抛出异常简单地说,或者如果在传输过程中丢失了少量数据,请参阅https://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/。 api非常相似,请参阅https://www.c-sharpcorner.com/article/asynchronous-videos-live-streaming-with-asp-net-web-apis-2-0/。重新实现可能有点麻烦,但我认为它会解决你的问题。
我的另一个见解是你尝试catch块指定它只接受IOExceptions,即使它正在捕获一个SocketException,大多数时候我只是使用通用的Exception类来避免尝试确定从哪里抛出哪些异常。
只是改变:
here
至
here
IOException和SocketException都继承自Exception类,因此其余代码保持不变。这应该可以为您提供更多问题特定信息。
你可能会遇到一些问题。
首先是TimeOut情况。有可能,因为你在互联网上遇到一些问题,请求和响应之间的时间大于指定的时间(我相信如果你没有,它默认设置为60秒)。
另一件事是文件大小可能很大,可以完全写入一个包响应。但这种情况会发生在任何请求中,而不仅仅发生在“糟糕的”互联网连接时刻。
也有可能因为互联网连接不稳定,你的“服务器”检测到“客户端”被发现(甚至是短暂的),因此关闭了套接字。