关闭所有基础网络连接
本文关键字:网络 连接 | 更新日期: 2023-09-27 18:28:33
背景:
我有一些代码正在连接到服务器以提取数据。然而,在某个时刻,程序进入了无法连接到服务器的状态。我们看到的问题是,当我们试图重新连接时,服务器不断超时。
插件:
我们将超时设置为网络插件(Thrift插件)使用的默认值。这些值分别为100k毫秒超时和300k毫秒读写超时。不是很短的暂停时间。此外,每次我们尝试重新连接时,我们都会重新创建插件的类,因此无论它在内部设置什么值,每次我们试图重新连接时都会重置。我认为暂停不是问题所在。我相信插件不是问题所在。
网络:
我们看到这些重复的超时现象持续了半个小时。当我们重新启动服务(而不是机器)时,它立即恢复在线。所以,我知道这不是网络问题。这让我相信是我们代码中的某些东西进入了无效的网络状态。此外,这是一种我们无法控制的状态,因为我们的插件向我们隐藏了所有好的网络内容,包括超时、保活标志和连接组(以及其他)。我们基本上没有访问HTTPWebRequest成员的权限。
问题:
当我们的网络设置进入这种状态时,我们会尝试关闭所有连接并重新连接到服务器。我们的目标是杀死所有活跃的连接,以便重置我们进入的任何状态。然而,当我们尝试重新连接时,我们的重新连接会超时。
不知何故(可能是由于我们无法控制的KeepAlive和TCP管道连接),即使我们关闭了所有连接,网络连接仍保持打开状态。这会使我们处于糟糕的状态,并阻止我们循环连接到服务器。
问题:
如何终止与服务器的所有底层连接以强制重新连接?
底层.Net架构将维护连接(通过KeepAlive),以提高整体网络性能。最简单的解决方案是在所有连接上将KeepAlive设置为false,这样它们就不会维护这些无效状态。不利的一面是,你会增加流量,因为他们每次都必须重新建立连接。
此外,由于无法访问keepalive(或HTTPWebRequest对象),您必须找到一种方法来终止请求设置之外的连接。
有两种方法可以让.Net释放这些连接。两者都涉及到ServicePoint级别和处理连接组。
-
关闭连接组
当您创建HTTPWebRequest时,您可以给它一个连接组。从那里,您可以使用ServicePoint的CloseConnectionGroup()函数来终止与该服务的所有连接。
ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri); srvrPoint.CloseConnectionGroup(myConnGroup)
当然,如果您有多个连接组,则需要对每个连接组进行循环。
请注意,如果选择此路径,请注意不要将所有连接都放在同一组中。这可能会导致套接字用完。点击此处了解更多信息。
-
释放所有连接组
ServicePoint类中有一个内部函数,您可以调用它来终止与给定服务点(即服务器)的所有连接。然而,因为它是类内部的,所以您必须使用反射来获取它:
ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri); MethodInfo ReleaseConns = srvrPoint.GetType().GetMethod ("ReleaseAllConnectionGroups", BindingFlags.Instance | BindingFlags.NonPublic); ReleaseConns.Invoke(srvrPoint, null);
这段代码只是从ServerPoint中提取ReleaseAllConnectionGroups,并在没有参数的情况下调用它。该函数将遍历其内部列表中的所有连接组,并释放所有这些资源——终止所有连接。
下降:因为这是一个私人会员,所以如果你升级你的.Net版本,你不能保证它会在那里。不过,它目前有2.0到4.5版本。指向ReleaseAllConnectionGroups的反向工程代码的链接。
由于无法设置连接组,因此必须使用选项2。
不幸的是,在不设置KeepAlive标志的情况下,没有其他方法可以让.Net关闭这些低级别连接并释放其KeepAliive状态。
为什么不使用以下代码:
SqlConnection.ClearAllPools();
我在所有的应用程序中都使用。