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

时间:2010-03-17 10:08:54

标签: c# wcf http tcp

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

考虑以下基本上是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连接。只有2个请求并行运行。它严重损害了处理速度。
  • 如果我切换到net.tcp绑定,一切正常(每个代理对象的单独TCP连接,即使它们在不同的机器上运行)。

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

2 个答案:

答案 0 :(得分:9)

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

实际上问题不在于服务配置或限制。实际上,如果客户端没有与它建立连接,服务器(WCF主机)就无法执行任何操作。在这种情况下,WCF客户端没有超过2个连接。我尝试了basicHttpBinding,WsHttpBinding甚至是旧的Web引用(asmx)方法。每个案例都没有超过2个连接。

此效果的根源在ServicePointManager.DefaultConnectionLimit属性,其默认值为2.此类位于System.Net命名空间中,该命名空间负责进行Http连接。显然,WCF和ASMX Web引用都使用System.Net命名空间来执行HTTP操作。这解释了为什么即使在多个线程中创建多个代理客户端之后我也无法发出多个服务请求。

总之,解决方案是将ServicePointManager.DefaultConnectionLimit设置为您希望从客户端进行的并发呼叫数。

答案 1 :(得分:1)

检查服务器限制 - 这是一个服务器端行为,您可以将其应用于服务器端配置:

<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