在C#中调整HttpWebRequest连接超时

JYe*_*ton 48 c# timeout httpwebrequest

我相信经过长时间的研究和搜索,我发现我想做的事情可能更好,通过建立一个异步连接并在所需的超时后终止它......但我会继续问,无论如何!

快速代码片段:

HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(url);
webReq.Timeout = 5000;
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse(); 
// this takes ~20+ sec on servers that aren't on the proper port, etc.
Run Code Online (Sandbox Code Playgroud)

我有一个HttpWebRequest多线程应用程序中的方法,我连接到大量的公司Web服务器.在服务器没有响应的情况下HttpWebRequest.GetResponse(),即使我指定的超时仅为5秒,大约需要20秒才能超时.为了定期通过服务器,我想跳过连接时间超过5秒的服务器.

所以问题是:"是否有一种简单的方法来指定/减少WebRequest或HttpWebRequest的连接超时?"

Rem*_*anu 57

认为问题在于WebRequest措施只是在实际提出请求之后的时间.如果您向同一地址提交多个请求,那么ServicePointManager将限制您的请求,并且实际上只提交与ServicePoint.ConnectionLimit默认从中获取值的相应值一样多的并发连接ServicePointManager.DefaultConnectionLimit.应用程序CLR主机将此设置为2,ASP主机设置为10.因此,如果您有一个多线程应用程序向同一主机提交多个请求,则实际上只有两个请求放在线路上,其余的排队等待.

我还没有研究过这个确凿的证据,证明这是不是真的发生了,但在一个类似的项目中,我有些事情是可怕的,直到我取消ServicePoint限制.

另一个要考虑的因素是DNS查找时间.同样,我相信没有确凿的证据支持,但我认为WebRequest不会计入请求超时的DNS查找时间.DNS查找时间可能会在某些部署中显示为非常大的时间因素.

是的,您必须围绕WebRequest.BeginGetRequestStream(对于POST带有内容的s)和WebRequest.BeginGetResponse(对于GETs POSTS s)编写应用程序.同步调用不会扩展(我不会详细说明为什么,但我确实有确凿的证据).无论如何,ServicePoint问题与此正交:排队行为也发生在同步调用上.

  • 我知道这个问题已经过时了,但我希望你能看到这个问题.您知道是否可以更改DNS解析超时?请在此处查看我的问题:http://stackoverflow.com/questions/5101507/c-web-calls-never-timing-out.我认为这与这个问题非常相似,并且DNS解析永远不会超时是有道理的.任何帮助表示赞赏. (2认同)
  • @mrnye:我对该主题发表了评论:系统范围的DNS解析参数:http://technet.microsoft.com/library/Cc977482 (2认同)

Tec*_*Sam 35

很抱歉找到一个旧线程,但我认为上面提到的内容可能不正确/误导.

从我所知道的.Timeout不是连接时间,它是HttpWebRequest和响应的整个生命周期所允许的总时间.证明:

我设置:

.Timeout=5000
.ReadWriteTimeout=32000
Run Code Online (Sandbox Code Playgroud)

HttpWebRequest的连接和发布时间为26ms

但随后的调用HttpWebRequest.GetResponse()在4974ms超时,从而证明5000ms是整个发送请求/获取响应调用集的时间限制.

我没有验证DNS名称解析是否作为时间的一部分被测量,因为这与我无关,因为这一切都不是我真正需要它工作的方式 - 我的意图是在连接到系统时更快地超时如果在请求的连接阶段失败,则不接受连接.

例如:我愿意在有可能返回结果的连接请求上等待30秒,但我只想等待10秒钟等待向一个行为不端的主机发送请求.

  • +1有用的添加主题,谢谢. (5认同)

JYe*_*ton 18

我后来发现的有帮助的东西是.ReadWriteTimeout财产.除了.Timeout属性之外,这似乎最终减少了线程花在尝试从有问题的服务器上下载的时间.默认时间.ReadWriteTimeout是5分钟,对我的应用来说太长了.

所以,在我看来:

.Timeout=尝试建立连接所花费的时间(不包括查找时间) .ReadWriteTimeout=在建立连接后尝试读取或写入数据所花费的时间

更多信息:HttpWebRequest.ReadWriteTimeout属性

编辑:

Per @KyleM的评论,该Timeout属性用于整个连接尝试,并在MSDN上阅读它显示:

Timeout是使用GetResponse方法进行的后续同步请求等待响应的毫秒数,GetRequestStream方法等待流.Timeout适用于整个请求和响应,而不是单独应用于GetRequestStream和GetResponse方法调用.如果在超时期限内未返回资源,则该请求将抛出WebException,并将Status属性设置为WebExceptionStatus.Timeout.

(强调我的.)

  • 只是注意到这个答案根本不是真的。正如 TechSavvySam 在之前对这个问题的回答中所说,.Timeout 是 FULL 连接请求和响应的限制。如果您的 .Timeout 设置为 5000 毫秒并且您的数据在 1000 毫秒开始发送,但需要 4999 毫秒才能完全发送,猜猜怎么着,您将超时。不管 API 文档怎么说,这就是现实世界的测试所显示的。 (3认同)
  • 我可以根据经验说明,在.NET 4.0中,无论文档僵硬的是什么,`.Timeout`属性似乎都不包含完整的响应.我有一个可重现的远程站点子集,允许快速建立连接,然后以非常慢的速度运行页面正文数据.尽管我将`.Timeout`设置为10秒,这导致连接总共很容易超过几分钟.但是,只要我**也将`.ReadWriteTimeout`设置为10秒,那么整个连接在10秒后就会根据需要中止. (2认同)

GBe*_*gen 14

从HttpWebRequest.Timeout属性的文档:

域名系统(DNS)查询最多可能需要15秒才能返回或超时.如果您的请求包含需要解析的主机名,并且您将Timeout设置为小于15秒的值,则在抛出WebException之前可能需要15秒或更长时间才能指示请求超时.

您的DNS查询是否可能是超时的原因?


Kar*_*non 8

无论我们尝试什么,当我们检查的服务器关闭时,我们无法设置超过21秒的超时.

为了解决这个问题,我们结合了一个TcpClient检查来查看域是否还活着,然后单独检查以确定URL是否处于活动状态

public static bool IsUrlAlive(string aUrl, int aTimeoutSeconds)
{
    try
    {
        //check the domain first
        if (IsDomainAlive(new Uri(aUrl).Host, aTimeoutSeconds))
        {
            //only now check the url itself
            var request = System.Net.WebRequest.Create(aUrl);
            request.Method = "HEAD";
            request.Timeout = aTimeoutSeconds * 1000;
            var response = (HttpWebResponse)request.GetResponse();
            return response.StatusCode == HttpStatusCode.OK;
        }
    }
    catch
    {
    }
    return false;

}

private static bool IsDomainAlive(string aDomain, int aTimeoutSeconds)
{
    try
    {
        using (TcpClient client = new TcpClient())
        {
            var result = client.BeginConnect(aDomain, 80, null, null);

            var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(aTimeoutSeconds));

            if (!success)
            {
                return false;
            }

            // we have connected
            client.EndConnect(result);
            return true;
        }
    }
    catch
    {
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)