5

私は困惑しています。おそらく、私が観察しているWCFクライアントの動作に誰かが光を当てることができます。

WCF サンプルを使用して、WCF クライアント/サーバー通信へのさまざまなアプローチを試してみました。1M のテスト リクエストを並行して実行している間、SysInternals TcpView を使用して開いているポートを監視していました。現在、クライアントを呼び出す方法は少なくとも 4 つあります。

  1. クライアントを作成し、必要なことを行い、GC に収集させます
  2. あなたのことをするよりも、usingブロックでクライアントを作成してください
  3. あなたのことをするよりも、usingブロックのファクトリからクライアントチャネルを作成します
  4. クライアントまたはチャネルを作成しますが、WCF 拡張機能を使用して自分のことを行います

現在、私の知る限り、オプション 2 ~ 4 のみが明示的に client.Close() を呼び出します。それらの実行中に、多くのポートが TIME_WAIT 状態のままになっていることがわかります。GC に依存しているため、オプション 1 が最悪のシナリオになると思います。しかし、驚いたことに、それらすべての中で最もクリーンであるように見えます。つまり、残存するポートを残しません。

私は何が欠けていますか?

更新: ソース コード

    private static void RunClientWorse(ConcurrentBag<double> cb)
    {
        var client = new CalculatorClient();
        client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service");
        RunClientCommon(cb, client);                        
    }

    private static void RunClientBetter(ConcurrentBag<double> cb)
    {
        using (var client = new CalculatorClient())
        {
            client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service");
            RunClientCommon(cb, client);
        }
    }

    private static void RunClientBest(ConcurrentBag<double> cb)
    {
        const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service";
        var address = new EndpointAddress(Uri);
        //var binding = new NetTcpBinding("netTcpBinding_ICalculator");
        using (var factory = new ChannelFactory<ICalculator>("netTcpBinding_ICalculator",address))
        {
            ICalculator client = factory.CreateChannel();
            ((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60);
            RunClientCommon(cb, client);
        }
    }

    private static void RunClientBestExt(ConcurrentBag<double> cb)
    {
        const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service";
        var address = new EndpointAddress(Uri);
        //var binding = new NetTcpBinding("netTcpBinding_ICalculator");
        new ChannelFactory<ICalculator>("netTcpBinding_ICalculator", address).Using(
            factory =>
                {
                    ICalculator client = factory.CreateChannel();
                    ((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60);
                    RunClientCommon(cb, client);
                });
    }
4

1 に答える 1

1

私はそれを理解したと思います。GC は ClientBase で Dispose を呼び出しません。これが、接続が TIME_WAIT 状態のままにならない理由です。そこで、同じパターンに従うことにし、新しい WCF 拡張機能を作成しました。

    public static void UsingAbort<T>(this T client, Action<T> work)
        where T : ICommunicationObject
    {
        try
        {
            work(client);
            client.Abort();
        }
        catch (CommunicationException e)
        {
            Logger.Warn(e);
            client.Abort();
        }
        catch (TimeoutException e)
        {
            Logger.Warn(e);
            client.Abort();
        }
        catch (Exception e)
        {
            Logger.Warn(e);
            client.Abort();
            throw;
        }
    }
}

このようにして、リクエストの最後に、接続を閉じるのではなく、単純に接続を中止します。

于 2013-05-08T17:23:40.403 に答える