为长时间运行的WCF应用程序选择正确的连接属性

kla*_*cht 2 wcf wcf-binding wcf-client

我正在使用WCF在C#中编写客户端/服务器应用程序.我的所有测试都没问题,但是一旦我部署了服务,我发现与服务器通信时出现了随机问题.我启用了调试并在服务器中看到了这样的消息:

The communication object, System.ServiceModel.Channels.ServerReliableDuplexSessionChannel, cannot be used for communication because it has been Aborted.
Run Code Online (Sandbox Code Playgroud)

模式是这样的:

  • 客户端正在发送查询
  • 服务正在处理查询
  • 服务正在发回一些东西
  • 活动边界处于"停止"水平 - 一切似乎都很好
  • 将可靠会话的inactivetivityTimeout添加到上次联系的日期时间,并且您具有服务抛出的异常的时间戳

应用程序如下所示:服务实例提供了与数据库交互的API方法,其类型为"netTcpBinding".几个客户端(大约40个)连接并从服务中随机调用方法.即使没有发送或接收任何东西,客户也可以保持开放几天.

以下是相关位:

服务:

    [ServiceContract(CallbackContract = typeof(ISVCCallback), SessionMode = SessionMode.Required)]
    [ExceptionMarshallingBehavior]
...
Run Code Online (Sandbox Code Playgroud)

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext=true)]
    public class SVCService : ISVC
...
Run Code Online (Sandbox Code Playgroud)

服务配置:

    <behaviors>
      <serviceBehaviors>
        <behavior name="behaviorConfig">
          <serviceMetadata httpGetEnabled="false" httpGetUrl="" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceThrottling maxConcurrentCalls="50" maxConcurrentSessions="1000"
            maxConcurrentInstances="50" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <netTcpBinding>
        <binding name="tcpBinding" closeTimeout="00:01:00" openTimeout="00:10:00"
          receiveTimeout="23:59:59" sendTimeout="00:01:30" transferMode="Buffered"
          listenBacklog="1000" maxBufferPoolSize="671088640" maxBufferSize="671088640"
          maxConnections="1000" maxReceivedMessageSize="671088640"     portSharingEnabled="true">
          <readerQuotas maxStringContentLength="671088640" maxArrayLength="671088640"
            maxBytesPerRead="671088640" />
          <reliableSession inactivityTimeout="23:59:59" enabled="true" />
          <security mode="None">
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
Run Code Online (Sandbox Code Playgroud)

客户端配置:

        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_ISVC" closeTimeout="00:01:00" openTimeout="00:10:00"
                    receiveTimeout="23:59:59" sendTimeout="00:01:30" transactionFlow="false"
                    transferMode="Buffered" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="1000"
                    maxBufferPoolSize="671088640" maxBufferSize="671088640" maxConnections="1000"
                    maxReceivedMessageSize="671088640">
                    <readerQuotas maxStringContentLength="671088640" maxArrayLength="671088640"
                        maxBytesPerRead="671088640" />
                    <reliableSession ordered="true" inactivityTimeout="23:59:59"
                        enabled="true" />
                    <security mode="None">
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
Run Code Online (Sandbox Code Playgroud)

这里有什么不对吗?这类应用程序的最佳配置是什么?

更新:

我遇到了一件事:

在一份服务合同中,我更改了一些内容并通知所有连接的客户.它通常很好,至少在我的测试中.但是最后"崩溃"或"冻结"我走过日志,看到最新的功能是我使用回调合同通知客户端的地方.

我想在那里做什么:我将一些东西保存到数据库中,最后我通知所有连接的客户端这个变化.我认为已连接的客户端列表不再是当前状态,并且在此步骤中会超时.

现在的问题是如何避免这些超时.

  • 我应该在服务中使用线程吗?我认为一旦服务呼叫结束,线程就会被杀死,我就在这里吗?
  • 我可以实现一个静态队列函数来执行所有回调通知(这是Marc_S建议的)
  • 有没有办法可靠地检测服务器内的连接丢弃?

mar*_*c_s 6

只是胡乱的想法:既然你的客户似乎过的时间(甚至几天)长期被发送消息,但似乎并没有给他们非常频繁 - 你能也许重新构建您的应用程序使用类似的消息队列中,而不是回调合约?

队列是解耦两个系统并减少超时潜力的好方法.

在基于队列的方案中,您的客户端会将消息放入队列(例如随Windows Server的每个副本一起提供的MSMQ),并且您的服务将在该传入队列上侦听消息.该服务将获取消息,处理它们,并且通常将某种响应消息放回第二个队列(客户端然后监听).

这里的主要好处是:

  • 你不需要相当脆弱和复杂的回叫合同设置
  • 您的系统已解耦,即使它们之间的连接断开几秒钟,几分钟,几小时也会继续工作
  • 您的服务可以响应传入的消息并发回更多"目标"响应,例如,某些客户端可以侦听"正常"响应队列,其他人则在"优先级"响应队列上等等 - 系统只是为您提供更大的灵活性IMO

查看更多资源:

并查看类似的东西

和其他系统(MassTransit等人)有利于排队通信,以在系统之间提供可靠的可扩展,可靠的消息传递.