httpWebRequest(底层连接已关闭:连接意外关闭。)

时间:2014-01-31 13:49:51

标签: c# httpwebrequest fiddler connectionexception

我正在开发一个从Web服务器记录数据的C#应用​​程序。它将以下发布请求发送到网络服务器并等待响应。

    /// <summary>
    /// Function for obtaining testCgi data 
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    private string HttpmyPost(string Parameters)
    {
        string str = "No response";
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTestCGI);
        request.Method = "POST";

        byte[] bytes = Encoding.UTF8.GetBytes(Parameters);
        request.ContentLength = bytes.Length;

        Stream requestStream = request.GetRequestStream();
        requestStream.Write(bytes, 0, bytes.Length);
        requestStream.Close();

            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream);

            try
            {
                var result = reader.ReadToEnd();
            stream.Dispose();
            str = result.ToString();
            reader.Dispose();
        }
        catch (WebException ex)
        {
            //System.Windows.Forms.MessageBox.Show(ex.Message);
            System.Diagnostics.Trace.WriteLine(ex.Message);

        }
        finally
        {
            request.Abort();
        }
        return str;
    }

我收到错误

> "The underlying connection was closed: The connection was closed
> unexpectedly"

我试图调试错误,并且我使用了fiddler来检查Firefox提供的post请求。令我惊讶的是,只要Fiddler在我的节目中工作得非常好。当我关闭提琴手时,我遇到了同样的错误。

我怀疑由于Fiddler充当代理,它可能会改变一些设置。 我尝试过使用webclient,结果是一样的。

当我尝试在python中编写请求时,一切正常,但没有任何问题。对于cource,我可以选择安装IronPython并包装该特定功能,但是我认为这有点过分且缺乏优雅,所以我正在追求更精简的方法。我怀疑这不过是一个设置调整。

我尝试过修改,在我的情况下,它是无关紧要的。

request.Accept 
request.ReadWriteTimeout 
request.Timeout 
request.UserAgent 
request.Headers
request.AutomaticDecompression 
request.Referer
request.AllowAutoRedirect
//request.TransferEncoding 
request.Expect
request.ServicePoint.Expect100Continue 
request.PreAuthenticate 
request.KeepAlive 
request.ProtocolVersion 
request.ContentType

无论是否进行上述调整,当Fiddler捕获数据时,代码都会起作用。

另外值得注意的是,该程序会在

处产生错误
WebResponse response = request.GetResponse();

更新: 按照@EricLaw的建议,我调查了Latency。 我找到了这篇文章 HttpWebRequest gets slower when adding an Interval 这表明转向Nagle算法。 现在没有关闭的连接,虽然整体响应有一个小的延迟(当我使用winforms而不是异步时)。

3 个答案:

答案 0 :(得分:28)

我写了一些关于Fiddler如何“神奇地”解决问题的方法:http://blogs.telerik.com/fiddler/posts/13-02-28/help!-running-fiddler-fixes-my-app-

您遇到的问题实际上是.NET Framework本身的一个错误。 HTTP的规则使得服务器可以在发送第一个响应之后随时关闭KeepAlive连接(例如,即使客户端请求KeepAlive行为,它也不需要接受连接上的另一个请求)。

.NET有一个错误,如果服务器在响应完成后关闭连接,它会期望服务器包含Connection: close响应头。如果服务器在没有Connection: Close标头的情况下关闭连接(根据RFC2616完全有效),则.NET在尝试在连接上发送下一个请求时将遇到关闭的连接,并且它将抛出此异常。 .NET 应该做的是静默创建新连接并在该新连接上重新发送请求。

Fiddler解决了这个问题,因为它不关心服务器是否关闭连接,并且它保持与客户端的连接活动。当客户端发送第二个请求时,Fiddler会尝试重用其与服务器的连接,注意到它已关闭,并以静默方式创建新连接。

您可以通过以下方式缓解代码中的此问题:

  1. 在请求中禁用keepalive(这会影响性能)
  2. 捕获异常并自动重试
  3. 更改服务器以使连接保持更长时间
  4. 方法#3仅在您控制服务器时有效,并且因为客户端可能位于使用后关闭连接的网关/代理后面,所以您应该使用方法#2。

答案 1 :(得分:0)

建议和问题: 1)如果你真的想看看安装Wireshark会发生什么。它会准确显示发送/接收的内容。它可以与小提琴手进行比较。 我猜你错过了一个标题,比如request.ContentType =&#34; ....&#34;但只有wireshark会告诉你哪一个(通过你的工作替代方式发送,而不是由你的HttpWebRequest发送)。

2)你是否在http响应内容中得到了错误,或者它是一个例外,如果它是一个异常,它会在你的catch中被捕获,或者在你的try语句之前发生在请求中?

答案 2 :(得分:-1)

Fiddler是一名互联网代理。如果您的代码在Fiddler运行时(也可能来自浏览器)运行,那么您的代理设置可能会出现问题。