【问题标题】:Catch unhandled SocketException during asynchronous HttpWebResponse read在异步 HttpWebResponse 读取期间捕获未处理的 SocketException
【发布时间】:2009-10-26 18:29:17
【问题描述】:

对 HttpWebRequest.BeginGetResponse/EndGetResponse 和 HttpWebResponse.GetResponseStream().BeginRead/EndRead 的所有异步调用都是由 try/catch 块进行的,但是,这些异常会传播并且不会留下机会来处理它们并停止应用程序终止:

未处理的异常:System.IO.IOException:无法从传输连接读取数据:已建立的连接被主机中的软件中止。 ---> System.Net.Sockets .SocketException: 已建立的连接被主机中的软件中止

未处理的异常:System.IO.IOException:无法从传输连接读取数据:现有连接被远程主机强行关闭。 ---> System.Net.Sockets.SocketException : 已存在的连接被远程主机强行关闭

Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine. ---> System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine
   at System.Net.Sockets.Socket.BeginReceive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)
   at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   --- End of inner exception stack trace ---
   at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.PooledStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.ConnectStream.BeginReadWithoutValidation(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.IO.Compression.DeflateStream.ReadCallback(IAsyncResult baseStreamResult)
   at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
   at System.Net.ContextAwareResult.CompleteCallback(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Net.ContextAwareResult.Complete(IntPtr userToken)
   at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
   at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

实际代码片段:

public static RequestState StartDownload(string url, string referer, RequestData data, DownloadEventHandler completedHandler, DownloadExceptionHandler failedHandler)
{
    RequestState state = null;

    try
    {
        var request = CreateWebRequest(url, referer, data);
        state = new RequestState(url, data, request)
        {
            DownloadCompleted = completedHandler;
            DownloadFailed = failedHandler;
        }

        state.ResponseAsyncResult = request.BeginGetResponse(WebResponseCallback, state);
        state.AsyncTimeoutHandle = ThreadPool.RegisterWaitForSingleObject(state.CompletedHandle, DownloadTimeoutCallback, state, TimeSpan.FromSeconds(data.DownloadTimeout), true);
    }
    catch(Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }

    return state;
}

private static void DownloadTimeoutCallback(object state, bool timedOut)
{
    var requestState = (RequestState)state;

    try
    {
        requestState.AsyncTimeoutHandle.Unregister(null);

        if(timedOut)
        {
            requestState.Request.Abort();
        }
    }
    catch(Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }
}

private static void WebResponseCallback(IAsyncResult asyncResult)
{
    var state = (RequestState)asyncResult.AsyncState;
    try
    {
        var response = (HttpWebResponse)state.Request.EndGetResponse(asyncResult);
        WebResponse(state, response);
    }
    catch (Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }
}

private static void WebResponse(RequestState state, HttpWebResponse response)
{
    state.ActualUrl = state.Request.Address.ToString();
    state.Response = response;

    BeginRead(state);
}

private static void BeginRead(RequestState state)
{
    var stream = state.Response.GetResponseStream();
    state.ReadAsyncResult = stream.BeginRead(state.Buffer, 0, state.BufferSize, ReadCallBack, state);
}

private static void ReadCallBack(IAsyncResult asyncResult)
{
    var state = (RequestState)asyncResult.AsyncState;

    try
    {
        var stream = state.Response.GetResponseStream();
        var bytesRead = stream.EndRead(asyncResult);

        if (bytesRead > 0)
        {
            //there is still more data to read
            state.AppendResponseData(state.Buffer, 0, bytesRead);
            BeginRead(state);
        }
        else
        {
            state.Response.Close();
            state.InvokeDownloadCompleted();
        }       
    }
    catch(Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }
}

PS:错误报告已提交至 Microsoft Connect https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564

【问题讨论】:

    标签: c# asynchronous httpwebrequest httpwebresponse beginreceive


    【解决方案1】:

    我认为原因是在与启动 BegainGetResponse 的线程不同的线程上引发了异常,这解释了调用堆栈中的 System.Threading.ExecutionContext.Run 调用。 情况可能是您在引发异常之前退出 try catch 块,因此它在没有处理程序的情况下引发,您能否发布您的部分代码,以便我了解如何改进它

    【讨论】:

    • 我认为您执行 BeginGetResponse 的地方缺少部分
    • 我认为这些与示例不太相关,但无论如何都包含更多代码 - 希望这能更好地解释问题。谢谢!
    【解决方案2】:

    Microsoft 于 2009 年 11 月 16 日上午 11:14 发布

    此问题已在 .NET 4.0 Framework 中解决。

    谢谢,

    网络类库团队

    https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564

    【讨论】:

    • 那么 .net 2 开发人员会发生什么,我应该去,但 Visual Studio 2010 还是有补丁?
    • @Smith,你发现了吗,我也有同样的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 2021-04-12
    • 2017-11-25
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多