【问题标题】:WCF Blocking problem with mutiple clients!多个客户端的 WCF 阻塞问题!
【发布时间】:2010-03-29 08:45:12
【问题描述】:

我似乎遇到了 WCF 的阻塞问题。

假设我有两个用户,每个用户都使用 net.tcp 创建了自己的类实例,该实例暴露在 WCF 主机上,端点类似于“net.tcp://localhost:32000/SymHost/”。该类是 PerSession 上下文,并发是可重入的。该类公开了两个方法 Alive() 立即返回一个布尔值 true 和一个我插入的 AliveWait ,它在返回 true 之前执行 Thread.Sleep 4 秒(测试目的)。

现在客户端 1 调用 AliveWait(),在此期间他被阻塞,这很公平,但是如果客户端 2 在其自己的实例上调用 Alive(),他必须等到客户端 1 的调用返回 - 这种行为是不是我所期望的?我本来希望客户端 2 继续进行,就好像什么都没发生一样,或者这与它们共享同一个端点的事实有关?

谁能解释发生了什么以及如何确保客户端 2 可以不间断地调用它自己的实例?

非常感谢任何帮助!

【问题讨论】:

    标签: wcf blocking net.tcp clients


    【解决方案1】:

    我发现了它是什么!我忘记在 Test 类的 ServiceBehaviour 中将 UseSynchronizationContext 设置为 false。这默认为 true ,它将服务上的所有调用同步到同一线程上运行!因此,来自其他客户端的任何后续呼叫都只是排队!

    【讨论】:

      【解决方案2】:

      向我们展示服务等级!光看你的描述,根本无法判断是怎么回事。

      期望客户端 2 会被客户端 1 阻止 - 在每个会话的情况下,两个客户端应该各自获得自己的、完全独立的服务类实例。这就是为什么我们需要看看我们在这里处理什么样的代码......通常,这种设置应该没有任何问题。

      【讨论】:

      • 这正是我的想法 - 我发布代码作为我的问题的答案,因为我超过了 500 个字符的限制!
      • 我通过查看 WCF 公开的每个属性发现了刚才的情况,而我忘记的是在 Test 类的 ServiceBehaviour 中将 UseSynchronizationContext 设置为 false。这默认为 true ,它将所有对服务的调用同步到同一线程上运行!因此,其他客户端的任何后续呼叫都只是排队!
      【解决方案3】:

      这正是我的想法!所以这里是一些源代码(经过一点复制和粘贴......):

      --合约定义

      [ServiceContract(CallbackContract = typeof(IAliveCallback))]
      public interface IAlive 
      {
          [OperationContract]
          bool Validate();
      
          [OperationContract]
          string AliveWait(int i);    // test test
      }
      

      -- 在我的 Alive 类中实现契约

      [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
      public class Alive : SymHostBase, IAlive
      {
          private readonly static string _ID = "Alive";
          private static int _MaxAliveWaitSeconds = 5;
      
          public bool Validate()
          {
              return true;
          }
      
          public string AliveWait(int i)
          {
              Thread.Sleep(i * 1000);
              return string.Format("I waited {0} seconds", i);
          }
      
      ...
      ...
      }
      

      -- 然后在主机应用程序上看起来像这样......

              string s = string.Format("net.tcp://localhost:{0}/Host/", port);
              Uri tcpAddr = new Uri(s);
              Uri[] baseAddress = { tcpAddr };
      
              int MaxBuffer = 64;     // 64 Mb
              int bufferSize = MaxBuffer * 1024 * 1024;   // 67108864
      
              NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None, true);
              tcpBinding.MaxBufferPoolSize = bufferSize; // 64 Mb
              tcpBinding.MaxBufferSize = bufferSize;
              tcpBinding.MaxReceivedMessageSize = bufferSize;
              tcpBinding.TransferMode = TransferMode.Buffered;
              tcpBinding.ReaderQuotas.MaxArrayLength = bufferSize;
              tcpBinding.ReaderQuotas.MaxBytesPerRead = bufferSize;
              tcpBinding.ReaderQuotas.MaxStringContentLength = bufferSize;
      
              tcpBinding.MaxConnections = 100;
              //tcpBinding.ReceiveTimeout = new TimeSpan(20, 0, 0);
              tcpBinding.SendTimeout = new TimeSpan(0, 0, 5);     
              tcpBinding.ReliableSession.Enabled = true;
              tcpBinding.ReliableSession.InactivityTimeout = new TimeSpan(7, 0, 0, 0);    // 7 days
      
      
              _HostAlive = new ServiceHost(typeof(Alive), baseAddress);
              _HostAlive.AddServiceEndpoint(typeof(IAlive), tcpBinding, "alive");      // tcpBinding
      
      
              ServiceThrottlingBehavior throttle = _HostAlive.Description.Behaviors.Find<ServiceThrottlingBehavior>();
              if (throttle == null)
              {
                  throttle = new ServiceThrottlingBehavior();
                  host.Description.Behaviors.Add(throttle);
              }
              throttle.MaxConcurrentCalls = 1000;         // default 16
              throttle.MaxConcurrentInstances = 1000;     // default 26
              throttle.MaxConcurrentSessions = 1000;      // default 10 
      
              // open the host - bring it into life!
              host.Open();
      

      【讨论】:

      • 能否请您更新您的原始问题,而不是发布一个虚拟答案?谢谢!
      • 您正在使用回调合约。该回调中有什么内容,谁在使用代理?它是一个 Winforms 应用程序,其中 UI 线程可能在执行回调时阻塞(->死锁)?
      • OK Marc 我下次更新问题!约翰,它是一个 WPF 应用程序。通常会使用回调,但在这种情况下根本不会使用。我有两个客户 - 一个有一个计时器并在其实例上反复调用 Alive() 并返回“真”。另一个客户端现在调用 AliveWait 3 秒,3 秒后调用回来 - 这个客户端一切正常。然而,计时器上的第一个客户已经发出了 3 个呼叫,直到第二个客户的呼叫完成,这些呼叫都没有得到应答!显然没有回调被调用,主机也没有做任何事情!
      • 代理被保留,所以主机可以回调,但我现在什么都不做!
      • 我自己找到的 - 我没有用 , UseSynchronizationContext=false 装饰的类!!!
      猜你喜欢
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      • 2021-02-15
      • 2017-04-18
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      • 2010-11-19
      相关资源
      最近更新 更多