14

我正在开发一个 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 给出的发布请求。令我惊讶的是,每当 Fiddler 是我的程序时,我的程序运行良好。当我关闭提琴手时,我遇到了同样的错误。

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

当我尝试在 python 中编写请求时,一切正常,没有问题。当然,我可以选择安装 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 的建议,我调查了延迟。我发现这篇文章 HttpWebRequest 在添加 建议打开 Nagle 算法的间隔时变慢。现在没有关闭的连接,尽管整体响应有一点滞后(当我使用 winforms,而不是异步时)。

4

3 回答 3

30

我在这里写了一些关于 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. 更改服务器以使连接保持更长时间

方法 #3 仅在您控制服务器时才有效,并且因为客户端可能位于使用后关闭连接的网关/代理后面,您可能也应该使用方法 #2。

于 2014-01-31T18:30:43.897 回答
0

一个建议和一个问题:1)如果你真的想看看发生了什么安装Wireshark。它将准确地向您显示正在发送/接收的内容。并且可以与提琴手进行比较。我猜您缺少一个标头,例如 request.ContentType = "...." 但只有 wireshark 会告诉您哪个标头(通过您的工作替代发送,而不是由您的 HttpWebRequest 发送)。

2)您是否在http响应内容中收到错误,或者它是一个异常,如果它是一个异常,它是在您的catch中捕获的,还是在请求期间发生,在您的try语句之前?

于 2014-01-31T14:16:22.230 回答
-1

Fiddler 用作 Internet 代理。如果您的代码在 Fiddler 运行时有效(也可能来自浏览器),那么您的代理设置可能有问题。

于 2014-01-31T14:26:19.173 回答