如何通过编程方式移除WebClient中的2个连接限制

90

"Fine"的RFC要求每个RFC客户端警惕不要在每个主机上使用超过2个连接……

微软在WebClient中实现了这一点。我知道可以通过

App.config将其关闭:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
 <system.net> 
  <connectionManagement> 
   <add address="*" maxconnection="100" /> 
  </connectionManagement> 
 </system.net> 
</configuration> 

(摘自http://social.msdn.microsoft.com/forums/en-US/netfxnetcom/thread/1f863f20-09f9-49a5-8eee-17a89b591007)

但我该如何以编程方式实现呢?根据http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit.aspx的说明:

"更改DefaultConnectionLimit属性对现有ServicePoint对象没有影响; 它仅影响在更改后初始化的ServicePoint对象。 如果未直接或通过配置设置此属性的值,则该值默认为常量DefaultPersistentConnectionLimit。"

我最想在实例化WebClient时配置限制,但如果在程序启动时以编程方式删除此限制也可以。

我访问的服务器不是互联网上的常规Web服务器,而是在本地网络中我控制的。 我想要进行API调用,但不使用Web服务或远程处理。


15
这并不是一个固定标准。RFC建议你将客户端连接数限制为2个,但这并不是必须的。很可能,发帖者需要同时下载超过2个文件。 - Erik Funkenbusch
12
我在自己的服务器上访问API。我不想对互联网上的主机造成伤害。 - Christian
12
我已将连接限制增加以构建一个负载测试工具。只使用两个连接进行负载测试非常困难。我相信有很多非浏览网页的原因需要使用更多的连接。 - ScottS
2
顺便提一下,上述配置会影响所有的 .Net 控制连接,而不仅仅是 webclient。 - ScottS
2
为什么只能是两个?让我们反过来问:为什么我不能异步地同时向服务器发出超过两个请求?2只是字面上的限制。 - Csaba Toth
显示剩余4条评论
5个回答

121

对于那些感兴趣的人:

System.Net.ServicePointManager.DefaultConnectionLimit = x(其中x是您所需的连接数)

不需要额外的引用

只需确保在创建服务点之前按照上述帖子中提到的方式调用此函数。


这个能加到全局的application_start里面吗?这样就会影响所有的连接了吧? - TheAlbear
如何在哪里添加 System.Net.ServicePointManager.DefaultConnectionLimit = x? - Arul Sidthan
奇怪的是,DefaultConnectionLimit的代码注释(使用F12导航)说它的默认值是Int32.MaxValue。然而,通过调试检查,它确实是2。 - crokusek

50

通过这里和其他地方的一些技巧,我成功地在我的应用程序中通过覆盖我正在使用的WebClient类来修复了这个问题:

class AwesomeWebClient : WebClient {
    protected override WebRequest GetWebRequest(Uri address) {
        HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
        req.ServicePoint.ConnectionLimit = 10;
        return (WebRequest)req;
    }
}

28
在我看来,设置System.Net.ServicePointManager.DefaultConnectionLimit是一种更好的解决方案,因为不能假设WebRequest是一个HttpWebRequest,例如,它可能是一个FileRequest - Dennis

7

这个解决方案允许您随时更改连接限制:

private static void ConfigureServicePoint(Uri uri)
{
    var servicePoint = ServicePointManager.FindServicePoint(uri);

    // Increase the number of TCP connections from the default (2)
    servicePoint.ConnectionLimit = 40;
}

第一次调用FindServicePoint时,会创建一个ServicePoint实例,并在ServicePointManager内部创建一个WeakReference来保存它。对于同一个Uri,后续的管理器请求将返回相同的实例。如果连接未被使用,则GC会将其清理掉。


1
FindServicePoint 的唯一问题是它会返回一个 ServicePoint,但你不知道它是否与客户端得到的是同一个 ServicePoint。 - jeffa00
2
这不是一个“问题”,而是工作的正常部分。与所有解决方案一样,您必须找到一种测试方法。我的方法是将.setting在.config中设置为“1”,观察可怕的性能,并将其设置在代码中(如此处所示),观察改善的性能。 - Abacus
1
MaxIdleTime 后,ServicePoint 将丢失(连同您的设置)。 - Colin Breame

5
如果您发现WebClient正在使用ServicePoint对象,则可以更改其连接限制。HttpWebRequest对象有一个访问器来检索它们构造时使用的对象,因此您可以通过这种方式进行更改。如果您很幸运,所有请求最终可能会共享同一个ServicePoint,因此您只需要执行一次即可。
我不知道是否有全局方式来更改限制。如果您在执行早期足够早地更改了DefaultConnectionLimit,则可能没有问题。
或者,您可以接受连接限制,因为大多数服务器软件都会对您进行限制。 :)

这个服务器不会限制我的速度(实际上,它会以不同的方式进行控制),因为它完全在我的掌控之中。 - Christian
1
一个服务器可能会因为连接过多而限制速度,但是即使是在一个小型服务器上(托管在有限的虚拟机中),我也没有遇到过这种情况。另一方面,客户端的连接限制却束缚了我。增加连接限制解放了局势。 - Csaba Toth
1
我也怀疑今天的任何浏览器是否会遵守HTTP 1.1 RFC的2个限制。 - Csaba Toth

4
我们有一个关于App.Config配置文件的问题。
为了在控制台应用程序中使其有效,我们添加了System.Configuration参考dll。没有这个参考,上述内容是无用的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接