关闭所有底层网络连接

时间:2013-08-22 12:20:05

标签: c# .net sockets network-programming

背景
我有一些代码连接到服务器来提取数据。但是,在某些时候程序进入了无法连接到服务器的状态。我们看到的问题是,当我们尝试重新连接时,服务器不断超时。

插件:
我们将超时设置为我们的网络插件(Thrift插件)使用的默认值。这些值是100k毫秒超时和300k毫秒读写超时。不完全是短暂的超时。此外,每次我们尝试重新连接时,我们都会重新创建插件的类,因此无论每次我们尝试重新连接时,内部设置的值都会重置。我认为超时不是问题。我相信这个插件不是问题。

网络:
我们看到这些重复超时发生了半个小时。当我们重新启动服务(而不是机器)时,它立即重新上线。所以,我知道这不是一个网络问题。这让我相信我们的代码中的某些内容正在进入无效的网络状态。此外,这是一个我们无法控制的状态,因为我们的插件隐藏了我们所有的好网络内容 - 包括超时,保持标记和连接组(以及其他)。我们基本上无权访问HTTPWebReqest成员。

问题:
当我们的网络设置进入此状态时,我们会尝试关闭所有连接并重新连接到服务器。目标是杀死所有活动连接,以便重置我们进入的状态。但是,当我们尝试重新连接时,我们的重新连接会超时。

不知何故(可能是由于KeepAlive和TCP Pipelining,我们无法控制),即使我们已关闭所有连接,网络连接仍保持打开状态。这使我们处于不良状态,并阻止我们将连接循环到服务器。

问题:
我如何杀死服务器的所有底层连接以强制重新连接?

2 个答案:

答案 0 :(得分:10)

底层的.Net架构将维护连接(通过KeepAlive),以提高整体网络性能。最简单的解决方案是在所有连接上将KeepAlive设置为false,以便它们不会保持这些无效状态。缺点是你会增加流量,因为他们每次都必须重新建立连接。

此外,由于您无权访问keepalive (或HTTPWebRequest对象),因此您必须找到一种方法来终止请求设置之外的连接。

有两种方法可以让.Net发布这些连接。它们都涉及到ServicePoint级别并处理连接组。

  1. <强> CloseConnectionGroups

    创建HTTPWebRequest时,可以为其指定连接组。从那里,您可以使用ServicePoint中的CloseConnectionGroup()函数来终止与该服务的所有连接。

    ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri);
    srvrPoint.CloseConnectionGroup(myConnGroup)
    

    当然,如果您有多个连接组,则需要在每个连接组的循环中执行此操作。

    请注意,如果选择此路径,请注意不要将所有连接放在同一组中。这可能会导致您的套接字耗尽。 More information here

  2. <强> ReleaseAllConnectionGroups

    ServicePoint类中有一个内部函数可以调用,它将终止与给定服务点(即服务器)的所有连接。但是,因为它是类的内部,所以你必须使用反射来实现它:

        ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri);
        MethodInfo ReleaseConns = srvrPoint.GetType().GetMethod
                ("ReleaseAllConnectionGroups",
                BindingFlags.Instance | BindingFlags.NonPublic);
        ReleaseConns.Invoke(srvrPoint, null);
    

    此代码只是从该ServerPoint中提取ReleaseAllConnectionGroup并在没有参数的情况下调用它。此功能将遍历其内部列表中的所有连接组,并释放所有这些资源 - 终止所有连接。

    垮台:因为这是私人会员,如果您升级.Net版本,则不能保证它会在那里。但它目前在版本2.0到4.5中可用。指向the reverse engineered code of ReleaseAllConnectionGroups

  3. 的链接

    由于无法设置连接组,因此您必须使用选项2.

    不幸的是,没有其他办法可以让.Net关闭那些低级连接并释放KeepAlive状态而不设置KeepAlive标志。

答案 1 :(得分:-2)

为什么不使用以下代码:

SqlConnection.ClearAllPools();

我在所有应用中使用它。