代码之家  ›  专栏  ›  技术社区  ›  Hemant

使用多个代理客户端时,如何修复WCF中的BasicHttpBinding?

  •  3
  • Hemant  · 技术社区  · 15 年前

    [问题似乎有点长,但请耐心等待。它有样本来源来解释问题。]

    请考虑以下基本上是wcf主机的代码:

    [ServiceContract (Namespace = "http://www.mightycalc.com")]
    interface ICalculator
    {
        [OperationContract]
        int Add (int aNum1, int aNum2);
    }
    
    [ServiceBehavior (InstanceContextMode = InstanceContextMode.PerCall)]
    class Calculator: ICalculator
    {
        public int Add (int aNum1, int aNum2) {
            Thread.Sleep (2000); //Simulate a lengthy operation
            return aNum1 + aNum2;
        }
    }
    
    class Program
    {
        static void Main (string[] args) {
            try {
                using (var serviceHost = new ServiceHost (typeof (Calculator))) {
                    var httpBinding = new BasicHttpBinding (BasicHttpSecurityMode.None);
                    serviceHost.AddServiceEndpoint (typeof (ICalculator), httpBinding, "http://172.16.9.191:2221/calc");
    
                    serviceHost.Open ();
                    Console.WriteLine ("Service is running. ENJOY!!!");
                    Console.WriteLine ("Type 'stop' and hit enter to stop the service.");
                    Console.ReadLine ();
    
                    if (serviceHost.State == CommunicationState.Opened)
                        serviceHost.Close ();
                }
            }
            catch (Exception e) {
                Console.WriteLine (e);
                Console.ReadLine ();
            }
        }
    }
    

    此外,WCF客户端程序是:

    class Program
    {
        static int COUNT = 0;
        static Timer timer = null;
    
        static void Main (string[] args) {
            var threads = new Thread[10];
    
            for (int i = 0; i < threads.Length; i++) {
                threads[i] = new Thread (Calculate);
                threads[i].Start (null);
            }
    
            timer = new Timer (o => Console.WriteLine ("Count: {0}", COUNT), null, 1000, 1000);
            Console.ReadLine ();
            timer.Dispose ();
        }
    
        static void Calculate (object state)
        {
            var c = new CalculatorClient ("BasicHttpBinding_ICalculator");
            c.Open ();
    
            while (true) {
                try {
                    var sum = c.Add (2, 3);
                    Interlocked.Increment (ref COUNT);
                }
                catch (Exception ex) {
                    Console.WriteLine ("Error on thread {0}: {1}", Thread.CurrentThread.Name, ex.GetType ());
                    break;
                }
            }
    
            c.Close ();
        }
    }
    

    基本上,我创建了10个代理客户端,然后在不同的线程上重复调用add service方法。现在,如果我运行这两个应用程序并使用netstat观察打开的TCP连接,我会发现:

    • 如果客户端和服务器都在同一台计算机上运行,则TCP连接数等于代理对象数。这意味着所有的请求都是并行的。这很好。
    • 如果我在一台单独的计算机上运行服务器,我观察到无论我创建多少代理对象,最多打开2个TCP连接。只有两个请求并行运行。这严重影响了处理速度。
    • 如果切换到net.tcp绑定,一切都会正常工作(即使每个代理对象在不同的计算机上运行,也会有一个单独的tcp连接)。

    我很困惑,无法使BasicHttpBinding使用更多的TCP连接。我知道这是一个很长的问题,但是请帮忙!

    2 回复  |  直到 15 年前
        1
  •  9
  •   Hemant    15 年前

    在花了两天时间解决这个问题之后,我找到了解决方案,所以让我在这里记录下来。

    实际上,问题不在于服务配置或限制。实际上,如果客户机未与其建立连接,服务器(wcf主机)将无法执行任何操作。在这种情况下,wcf客户端没有建立超过2个连接。我尝试了BasicHttpBinding、wsHttpBinding,甚至还尝试了旧的Web引用(Asmx)方法。每个案例都无法建立两个以上的连接。

    这种效应的根源在于 ServicePointManager.DefaultConnectionLimit 默认值为2的属性。此类位于负责建立HTTP连接的System.NET命名空间中。显然,wcf和asmx web引用都使用system.net名称空间来完成它们的http任务。这解释了为什么即使在多个线程中创建了多个代理客户端,我也无法发出多个服务请求。

    总之,解决方案是 ServicePointManager.DefaultConnectionLimit 要从您的 客户机 .

        2
  •  1
  •   marc_s    15 年前

    签出服务器限制-这是一种服务器端行为,可以应用于服务器端配置:

    <system.serviceModel>
        <services>
          <service 
            name="Microsoft.WCF.Documentation.SampleService"
            behaviorConfiguration="Throttled" >
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8080/SampleService"/>
              </baseAddresses>
            </host>
            <endpoint
              address=""
              binding="wsHttpBinding"
              contract="Microsoft.WCF.Documentation.ISampleService"
             />
            <endpoint
              address="mex"
              binding="mexHttpBinding"
              contract="IMetadataExchange"
             />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="Throttled">
              <serviceThrottling 
                maxConcurrentCalls="1" 
                maxConcurrentSessions="1" 
                maxConcurrentInstances="1" />
              <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    

    看到这个 blog post 有关详细信息,请查看 MSDN docs on Service Throttling