代码之家  ›  专栏  ›  技术社区  ›  Remy

httpContext.Response基础套接字意外关闭

  •  6
  • Remy  · 技术社区  · 7 年前

    我有一个 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
    {
       responseStream.Write(totalBufferdata.ToArray(), 0, totalBufferdata.Count);//write all data in totalBufferData to the response
    }
    catch (IOException e)
    {
       Debug.LogError("Exception in writing to response::" + e);
       Debug.LogError("innerException:: " + e.InnerException);
    }
    responseStream.Close();//close the request and response stream
    

    这将通过请求的上下文(即192.168.0.10/foobar.ext,通过同一端口)发送响应。

    现在这个很好用, 只要有快速、可靠的互联网连接 . 当Internet连接缓慢或不一致时,我开始获取异常:

    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 卷曲至 on msdn 但那只是“e眀失败未指明的失败”,所以没有运气。

    我一直不明白为什么它会抛出关闭套接字的预期(以及为什么它发生在 本地服务器 部分,但 只有 当连接不良时)。我确定 全部的 所需数据在 totalBufferData 因此,低网速不应该影响这一点,因为在我将数据写入响应之前,所有数据都已下载。我确保在代码中的任何地方都不会过早关闭上下文。

    到目前为止,我一直没有找到一种方法来找到 霍特普林斯特 . 我也试过铸造 response.OutputStream 到A NetworkStream 从networkstream中获取套接字,但该转换无效(这会使我困惑,因为它们都是IO流?).我认为这可能是一个收尾问题,我也尝试过

    using(Stream testStream = response.OutputStream)
    {
        testStream.Write(totalBufferdata.ToArray(), 0, totalBufferdata.Count);
    }
    

    我觉得这个问题与超时有关 在某处 . 但侦听器不会命中默认的超时时间。根据 to MSDN 所有默认超时应为2分钟。我在30秒到1分钟后得到错误。我认为在超时的情况下返回的异常应该是 ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed. 正如我想象的那样,超时会处理连接,而不是崩溃?这是误会吗?

    请求和响应是在单独的线程上完成的。但是,当响应仍在进行中时完成的请求将排队,并等待响应完成,然后再启动新的响应。

    有没有一种方法来获取和调试底层套接字,以找出它关闭/崩溃的原因?或者是在本地主机上请求文件并对不使用的文件作出响应的另一种方法。 霍特普林斯特 ?

    一些附加信息:它适用于使用脚本运行时版本.NET 4.x的Unity应用程序(Unity 2019.1),具有.NET 4.x API兼容级别和IL2CPP脚本后端。但是,处理请求或响应的类都没有继承自monobeviour(在统一的线程上这甚至是不可能的)。为Android构建。


    赏金已经结束了,但我还是会给有一些有价值的信息的人100分!

    4 回复  |  直到 7 年前
        2
  •  0
  •   iggy12345    7 年前

    这听起来像是我以前遇到的一个问题,鉴于互联网速度慢或不可靠,我建议可能使用UDP套接字而不是TCP,因为它们不会在连接短暂中断时抛出异常,或者如果在传输过程中丢失少量数据,请参阅 here . API非常类似,请参见 here . 重新实施可能会有点麻烦,但我认为这会解决你的问题。

    我的另一个见解是,您的try-catch块指定它只接受IOExceptions,即使它捕获的是socketException,大多数时候我只是使用泛型异常类来避免尝试确定从何处抛出哪些异常。

    只是改变:

    catch (IOException e)
    

    catch (Exception e)
    

    IOException和SocketException都继承自Exception类,因此其余代码保持不变。希望这能给你一些更具体的问题信息。

        3
  •  0
  •   Remy    7 年前

    虽然我还没有找到 修理 对于最初的问题,我已经找到了解决这个问题的方法。

    最初我做的是下载 整个的 文件,然后将文件中的数据发送回 HttpContext.Response.OutputStream . 如果下载文件花费的时间太长,则有时会超时。

    我现在做的是如果我发送 小包裹 httpContext.Response.Outputstream 当一个包被完全下载时。然后当所有的包都被下载并且文件的下载已经完成时,我调用 Response.Close() 关闭溪流。

    由于这个原因,连接会更快地得到较小的数据块,因为它不需要等待整个文件首先被下载。这反过来又似乎阻止了插座的缩小。(我所期望的是发生在引擎盖下的事情。)

    由于额外的好处,下载速度明显提高(大约快1.7倍)。虽然我知道为什么这会提高下载速度。如果有人对此有想法,请发表评论。

        4
  •  -1
  •   SammuelMiranda    7 年前

    你可能有一些问题。

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

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

    也有可能,因为Internet连接不稳定,“服务器”检测到“客户机”断开(甚至短暂断开),因此关闭了套接字。