【问题标题】:WCF Service concurrency issues and timeoutsWCF 服务并发问题和超时
【发布时间】:2012-11-10 07:11:58
【问题描述】:

我有一个 WCF 服务,它从一个应用程序接收消息并向其他连接的客户端应用程序发送通知。

在我的第一个测试场景中,一个客户端应用程序每秒向服务发送大量消息,而另外两个应用程序正在从服务接收这些消息。在此测试中,我的服务运行良好。

但是,如果我添加另一个发送消息的客户端应用程序(2 个应用程序向服务发送消息)应用程序崩溃并抛出超时异常(大多数情况下是 SendTimeOut)。

第二次测试每秒的消息量低于第一次测试,因为我在请求之间使用了Thread.Sleep(),所以我认为问题在于发送请求的应用程序数量多于请求数量,但我不确定。

你知道为什么会出现这些问题吗?

我的服务和客户端应用程序编码如下:

服务合同:

[ServiceContract(CallbackContract = typeof(ICacheCommunicatorServiceCallback), SessionMode = SessionMode.Required)]
public interface ICacheCommunicatorService
{
    [OperationContract(IsInitiating = true, IsOneWay = true)]
    void Connect(string appName, string machineName);

    [OperationContract(IsTerminating = true, IsOneWay = true)]
    void DisconnectClient(ICacheCommunicatorServiceCallback callback);

    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginSendNotification(Notification notification, AsyncCallback callback, object state);
    void EndSendNotification(IAsyncResult result);
}

请求方法代码:

public IAsyncResult BeginSendNotification(Notification notification, AsyncCallback callback, object state)
    {
        try
        {
            ICacheCommunicatorServiceCallback current = CurrentCallback;

            ClientInfo sender = clients[current];

            foreach (ICacheCommunicatorServiceCallback client in clients.Keys)
            {                   
                if (client != current)
                {                       
                    if (((ICommunicationObject)client).State == CommunicationState.Opened)
                    {
                        client.ReceiveNotification(notification);
                    }
                    else
                    {
                        DisconnectClient(client);
                    }
                }
            }
        }
        catch (Exception e)
        {
            Log(e);
        }
        return new CompletedAsyncResult();
    }

    public void EndSendNotification(IAsyncResult asyncResult) { }

服务配置:

 <system.serviceModel>
<services>
  <service behaviorConfiguration="DefaultBehavior" name="CacheCommunicator.CacheCommunicatorService">
    <endpoint address="tcp" binding="netTcpBinding" bindingConfiguration="tcpBindingConfiguration"
      name="TcpEndpoint" contract="CacheCommunicator.ICacheCommunicatorService">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" name="MexEndpoint" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8733/CacheCommunicator/" />
        <add baseAddress="http://localhost:8732/CacheCommunicator/" />
      </baseAddresses>
    </host>
  </service>
</services>
<bindings>
  <netTcpBinding>
    <binding name="tcpBindingConfiguration"
             closeTimeout="00:00:05"
             maxBufferSize="1048576"
             maxBufferPoolSize="1048576"
             maxConnections="10"
             maxReceivedMessageSize="1048576"
             openTimeout="00:00:05"
             receiveTimeout="01:00:00"
             sendTimeout="01:00:00"
             transferMode="Buffered">
      <readerQuotas maxArrayLength="1048576" maxBytesPerRead="1048576" maxStringContentLength="1048576"/>
      <reliableSession enabled="false" inactivityTimeout="01:00:00"/>
    </binding>
  </netTcpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior name="DefaultBehavior">
      <serviceMetadata httpGetEnabled="True"/>
      <serviceDebug includeExceptionDetailInFaults="True" />
    </behavior>
  </serviceBehaviors>
</behaviors>

客户端请求调用:

internal void SendNotification(Notification notification)
    {
        if (!isConnected()) this.Connect();

        Task.Factory.StartNew(() =>
        {
            proxy.SendNotification(notification);    
        }).HandleExceptions();
    }

客户端应用配置:

 <system.serviceModel>
<bindings>
  <netTcpBinding>
    <binding name="TcpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
      <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
      <security mode="Transport">
        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
        <message clientCredentialType="Windows"/>
      </security>
    </binding>
  </netTcpBinding>
</bindings>

【问题讨论】:

    标签: .net wcf wcf-binding wcf-client


    【解决方案1】:

    尝试为服务器 WCF 服务显式设置限制设置:

    <serviceBehaviors>
       <behavior name="ServiceBehavior">
           <serviceThrottling maxConcurrentCalls="200"
                              maxConcurrentInstances ="100" 
                              maxConcurrentSessions ="100"/>
       </behavior>
    </serviceBehaviors>
    

    顺便说一句,哪个 ConcurrrencyMode / InstanceMode 用于 WCF 服务?

    建议阅读:

    【讨论】:

    • 感谢您的回答。 WCF 服务使用 InstanceMode.Single 和 ConcurrencyMode.Multiple。
    【解决方案2】:

    确保每次调用后都在客户端代理上调用 .Close()。您可以通过一个代理实例进行多次调用,但在完成客户端调用后始终使用 .Close()。

    【讨论】:

      猜你喜欢
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 2010-09-18
      相关资源
      最近更新 更多