HttpContext.Response底层套接字意外关闭

问题描述 投票:6回答:3

我有一个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构建。


赏金已经结束,但我会为有任何有价值信息的人开一个新的!

c# sockets unity3d networking httplistener
3个回答
0
投票

请参阅此博客文章,了解如何使用带有ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed.的aspnet webapi来传输视频文件。

HttpListener

PushStreamContent


0
投票

这听起来像是我之前遇到过的一个问题,由于互联网速度慢或不可靠,我建议可能要使用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类,因此其余代码保持不变。这应该可以为您提供更多问题特定信息。


-1
投票

你可能会遇到一些问题。

首先是TimeOut情况。有可能,因为你在互联网上遇到一些问题,请求和响应之间的时间大于指定的时间(我相信如果你没有,它默认设置为60秒)。

另一件事是文件大小可能很大,可以完全写入一个包响应。但这种情况会发生在任何请求中,而不仅仅发生在“糟糕的”互联网连接时刻。

也有可能因为互联网连接不稳定,你的“服务器”检测到“客户端”被发现(甚至是短暂的),因此关闭了套接字。

© www.soinside.com 2019 - 2024. All rights reserved.