7

我正在开发一个 winform 应用程序,该应用程序将访问作为 Windows 服务自托管的 WCF 服务。我使用的是 ChannelFactory 而不是服务参考。我已经成功连接和调用了WCF服务。问题是当我让应用程序保持空闲 20 分钟,然后尝试拨打另一个电话时。我收到以下错误:

“套接字连接被中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或底层网络资源问题造成的。本地套接字超时为 '00:00:59.9489970'。”

我正在寻找管理连接的最佳实践。我目前创建了一个名为 PrepareWCFConnection(见下文)的函数,用于检查通道和 ChannelFactory 的状态。在对 WCF 服务进行任何调用之前,我会调用此方法。有没有更好的方法来处理这个?

     public bool PrepareWCFConnection()
    {
        if ((channelFactory == null) || 
            (channelFactory.State == CommunicationState.Faulted) ||
            (channelFactory.State != CommunicationState.Opened))
        {
            channelFactory = new ChannelFactory<IService1>(new NetTcpBinding(), endpointAddress);
        }


        if ((proxy == null) ||
            (((IClientChannel)proxy).State == CommunicationState.Faulted) ||
            (((IClientChannel)proxy).State != CommunicationState.Opened))
        {
            proxy = channelFactory.CreateChannel(endpointAddress);
            ((IClientChannel)proxy).Open();
        }

        return true;
    }
4

3 回答 3

6

如果您想重用现有频道,您需要通过每 9 分钟 ping 一次服务来保持频道处于活动状态。我认为默认接收超时为 10 分钟,因此如果频道保持空闲超过此时间,则会断开连接。或者您可以使用可靠的会话来保持频道活跃。

如果您不需要在同一个频道上回调,最好在完成后关闭频道并为每个服务操作重新创建一个新频道。创建频道并不昂贵。您可以缓存频道工厂,但是为每次通话创建频道。

于 2013-02-12T10:44:10.137 回答
2

我知道这个问题现在已经很老了,但我发现它并没有真正得到回答。有两个超时(如果您不使用可靠消息传递,则只有 1 个)当涉及到通道超时时,您应该关注。在服务端,如果在超时期限内未收到应用程序消息,则会触发“ReceiveTimeout”。此超时的默认值为 10 分钟。

还有“InactivityTimeout”,仅在启用“ReliableSession”时使用。此超时是通道允许其他通信方在通道发生故障之前不发送任何消息的最大持续时间。

为了增加频道的生命周期,我建议您启用“ReliableSession”,然后将“ReceiveTimeout”和“InactivityTimeout”设置为更高的值。ReliableSession 通过发送 ILM(基础设施级消息)来保持通道活动,例如 keep-alive(也发送 ack)。如果在“InactivityTimeout”到期之前未收到保持活动或 ALM(应用程序级别消息),则通道将出现故障。

此外,如果在“ReceiveTimeout”到期之前没有收到 ALM(应用程序级消息),则通道将出现故障。

因此,建议将两个超时设置为相同的值,或者将“ReceiveTimeout”设置为高于“InactivityTimeout”的值。

附带说明,在客户端设置时设置“ReceiveTimeout”将无效,它只是服务端超时。但是在服务端使用 ReliableSession 时,客户端也必须像这样实现它:

NetTcpBinding binding = new NetTcpBinding
        {
            ReliableSession = { Enabled = true },             
            SendTimeout = TimeSpan.FromMinutes( 1 )
        };

        binding.ReliableSession.InactivityTimeout = TimeSpan.Parse( "24.20:31:23.6470000" );

服务端的 app.config 看起来像这样:

<bindings>
    <netTcpBinding>
      <binding name="netTestTcpBinding"
               receiveTimeout="24.20:31:23.6470000">
        <reliableSession inactivityTimeout="24.20:31:23.6470000"
                         enabled="true" />
      </binding>
    </netTcpBinding>
  </bindings>
<services>
  <service>
    <endpoint address="IServiceContract"
              binding="netTcpBinding"
              bindingConfiguration="netTestTcpBinding"
              name="serviceContractTcpBinding"/>
    <host>
        <baseAddresses>
             <add baseAddress="net.tcp://localhost:12001/" />
        </baseAddresses>
     </host>
    </service>                   
</services>
于 2016-02-08T15:06:36.433 回答
0

一个非常直接的解决方案可以重用您的频道,无需轮询或做一些花哨的事情,它只需处理对您的频道的最后一次调用并检查 wcfC.Binding.ReceiveTimeout 以便在需要时重新生成它,例如:

    TimeSpan timeSpan = DateTime.Now - LastCallTime;
    if (timeSpan.TotalSeconds > wcfC.Binding.ReceiveTimeout.TotalSeconds || wcfC.State != CommunicationState.Opened)
    { 
       wcfC.Abort();
       wcfC = new WCFChannel();

    }    
    LastCallTime = DateTime.Now;
于 2017-06-08T11:03:36.373 回答