在 C# 中调整 HttpWebRequest 连接超时

发布于 2024-08-06 11:34:07 字数 629 浏览 2 评论 0原文

我相信经过长时间的研究和搜索,我发现通过设置异步连接并在所需的超时后终止它可能会更好地满足我想要做的事情......但无论如何我都会继续询问!< /em>

快速代码片段:

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.

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

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

I believe after lengthy research and searching, I have discovered that what I want to do is probably better served by setting up an asynchronous connection and terminating it after the desired timeout... But I will go ahead and ask anyway!

Quick snippet of code:

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.

I have an HttpWebRequest method that is in a multi-threaded application, in which I am connecting to a large number of company web servers. In cases where the server is not responding, the HttpWebRequest.GetResponse() is taking about 20 seconds to time out, even though I have specified a timeout of only 5 seconds. In the interest of getting through the servers on a regular interval, I want to skip those taking longer than 5 seconds to connect to.

So the question is: "Is there a simple way to specify/decrease a connection timeout for a WebRequest or HttpWebRequest?"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橘虞初梦 2024-08-13 11:34:07

我相信问题在于 WebRequest 仅在实际发出请求后才测量时间。如果您向同一地址提交多个请求,则 ServicePointManager 将限制您的请求,并且仅实际提交与相应 ServicePoint.ConnectionLimit 默认情况下从 ServicePointManager.DefaultConnectionLimit。应用程序 CLR 主机将此设置为 2,ASP 主机设置为 10。因此,如果您有一个多线程应用程序向同一主机提交多个请求,则实际上只有两个请求被放置在线路上,其余的将排队。

我还没有研究过这是否确实发生了确凿的证据,但在一个类似的项目中,我遇到了可怕的事情,直到我删除了 ServicePoint 限制。

另一个需要考虑的因素是 DNS 查找时间。再说一次,我的信念没有确凿的证据支持,但我认为 WebRequest 确实没有根据请求超时计算 DNS 查找时间。在某些部署中,DNS 查找时间可能会显示为非常大的时间因素。

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

I believe that the problem is that the WebRequest measures the time only after the request is actually made. If you submit multiple requests to the same address then the ServicePointManager will throttle your requests and only actually submit as many concurrent connections as the value of the corresponding ServicePoint.ConnectionLimit which by default gets the value from ServicePointManager.DefaultConnectionLimit. Application CLR host sets this to 2, ASP host to 10. So if you have a multithreaded application that submits multiple requests to the same host only two are actually placed on the wire, the rest are queued up.

I have not researched this to a conclusive evidence whether this is what really happens, but on a similar project I had things were horrible until I removed the ServicePoint limitation.

Another factor to consider is the DNS lookup time. Again, is my belief not backed by hard evidence, but I think the WebRequest does not count the DNS lookup time against the request timeout. DNS lookup time can show up as very big time factor on some deployments.

And yes, you must code your app around the WebRequest.BeginGetRequestStream (for POSTs with content) and WebRequest.BeginGetResponse (for GETs and POSTSs). Synchronous calls will not scale (I won't enter into details why, but that I do have hard evidence for). Anyway, the ServicePoint issue is orthogonal to this: the queueing behavior happens with async calls too.

若沐 2024-08-13 11:34:07

很抱歉继续旧话题,但我认为上面所说的内容可能不正确/具有误导性。

据我所知,超时不是连接时间,而是 HttpWebRequest 和响应的整个生命周期允许的总时间。证明:

我设置:

.Timeout=5000
.ReadWriteTimeout=32000

HttpWebRequest 的连接和发布时间花费了 26 毫秒,

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

我没有验证 DNS 名称解析是否作为时间的一部分进行测量,因为这与我无关,因为这些都没有按照我真正需要的方式工作——我的目的是在连接到以下系统时更快地超时不接受连接,如它们在请求的连接阶段失败所示。

例如:我愿意在有机会返回结果的连接请求上等待 30 秒,但我只想花 10 秒的时间来等待向行为异常的主机发送请求。

Sorry for tacking on to an old thread, but I think something that was said above may be incorrect/misleading.

From what I can tell .Timeout is NOT the connection time, it is the TOTAL time allowed for the entire life of the HttpWebRequest and response. Proof:

I Set:

.Timeout=5000
.ReadWriteTimeout=32000

The connect and post time for the HttpWebRequest took 26ms

but the subsequent call HttpWebRequest.GetResponse() timed out in 4974ms thus proving that the 5000ms was the time limit for the whole send request/get response set of calls.

I didn't verify if the DNS name resolution was measured as part of the time as this is irrelevant to me since none of this works the way I really need it to work--my intention was to time out quicker when connecting to systems that weren't accepting connections as shown by them failing during the connect phase of the request.

For example: I'm willing to wait 30 seconds on a connection request that has a chance of returning a result, but I only want to burn 10 seconds waiting to send a request to a host that is misbehaving.

夜吻♂芭芘 2024-08-13 11:34:07

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

所以,在我看来:

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

更多信息:HttpWebRequest.ReadWriteTimeout 属性

编辑:

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

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

(强调我的。)

Something I found later which helped, is the .ReadWriteTimeout property. This, in addition to the .Timeout property seemed to finally cut down on the time threads would spend trying to download from a problematic server. The default time for .ReadWriteTimeout is 5 minutes, which for my application was far too long.

So, it seems to me:

.Timeout = time spent trying to establish a connection (not including lookup time)
.ReadWriteTimeout = time spent trying to read or write data after connection established

More info: HttpWebRequest.ReadWriteTimeout Property

Edit:

Per @KyleM's comment, the Timeout property is for the entire connection attempt, and reading up on it at MSDN shows:

Timeout is the number of milliseconds that a subsequent synchronous request made with the GetResponse method waits for a response, and the GetRequestStream method waits for a stream. The Timeout applies to the entire request and response, not individually to the GetRequestStream and GetResponse method calls. If the resource is not returned within the time-out period, the request throws a WebException with the Status property set to WebExceptionStatus.Timeout.

(Emphasis mine.)

拥抱没勇气 2024-08-13 11:34:07

无论我们如何尝试,当我们检查的服务器关闭时,我们都无法将超时时间控制在 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;
}

No matter what we tried we couldn't manage to get the timeout below 21 seconds when the server we were checking was down.

To work around this we combined a TcpClient check to see if the domain was alive followed by a separate check to see if the URL was active

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;
}
囚我心虐我身 2024-08-13 11:34:07

来自 HttpWebRequest.Timeout 属性的文档:

域名系统 (DNS) 查询可能会
最多需要 15 秒才能返回或
暂停。如果您的请求包含
需要解析的主机名和
您将超时设置为小于
15 秒,可能需要 15 秒或
在抛出 WebException 之前进行更多操作
指示您的请求超时。

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

From the documentation of the HttpWebRequest.Timeout property:

A Domain Name System (DNS) query may
take up to 15 seconds to return or
time out. If your request contains a
host name that requires resolution and
you set Timeout to a value less than
15 seconds, it may take 15 seconds or
more before a WebException is thrown
to indicate a timeout on your request.

Is it possible that your DNS query is the cause of the timeout?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文