6

我有一个简单的 WCF 双工 TCP 服务,我试图以编程方式停止它。如果我没有任何连接的用户,ServiceHost.Close() 非常快,但如果我什至有一个连接的用户,我发现 Close() 函数需要相当长的时间,有时 > 30 秒。这是通常的行为吗?

另一方面, Abort() 几乎是瞬时的,我很想改用它。

4

5 回答 5

10

可能是。文档指出_

Close 方法允许在返回之前完成任何未完成的工作。例如,完成发送任何缓冲的消息。

有一个过载Close()需要一个TimeSpanthrows如果超过时间跨度)

Abort()看起来像是立即停止 WCF 主机的最佳方法。

于 2009-06-22T02:07:44.250 回答
8

确保您正在关闭客户端连接,如下所示:

var channel = factory.CreateChannel();
var channel.DoSomethingForMe();
(channel as ICommunicationObject).Close();

如果您不在通道上执行此 Close(),则服务器上的 Close() 会等待非常非常长的时间,即使您指定了很短的超时时间也是如此。

于 2012-10-02T01:08:17.320 回答
1

如果您可以终止任何正在进行的服务调用,那么 Abort() 就是要走的路。Close() 是关闭服务的礼貌方式。

于 2009-08-30T19:05:19.057 回答
0

为了权宜之计,我可以看到 Abort() 优于 Close() 的好处,但我想可能会发生一些不好的事情。就我而言,我想等待 Close() 以便我可以重用端口。此代码将在恢复之前等待服务实际关闭。

Semaphore cont=new Semaphore(0, 1);
foreach (ServiceHost s in WCFServices) {
    try {
        s.Closed += delegate(Object o, System.EventArgs n) {
            cont.Release();
        };
        s.Close();
        cont.WaitOne();                 
    } catch (Exception) {
    }//try
}//for
于 2010-04-06T13:33:57.073 回答
0

我也注意到了这个问题。我的代码最初看起来像这样:

[TestMethod]
[Timeout(2000)]
public void ApiClientTest()
    {
        bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false;
        Api apiService = new ApiTestService();
        var clientService = new ClientTestService();

        ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService));
        ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService));

        //To let us know the services were successfully opened
        clientHost.Opened += (s, e) => ClientSuccessSet = true;
        apiHost.Opened += (s, e) => ApiSuccessSet = true;
        clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName);
        apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName);
        clientHost.BeginOpen(OnOpen, clientHost);
        apiHost.BeginOpen(OnOpen, apiHost);

        //This allows both services to be open for communication.
        while (!ApiSuccessSet || !ClientSuccessSet)
            Thread.Yield();


        EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName);
        EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName);

        InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback());
        var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint);
        var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint);
        var ClientChannel = ClientChannelFactory.CreateChannel();
        var ApiChannel = ApiChannelFactory.CreateChannel();


        clientHost.Close();
        apiHost.Close();
    }

void OnOpen(IAsyncResult ar)
    {
        ServiceHost service = (ServiceHost)ar.AsyncState;
        service.EndOpen(ar);
    }

我注意到这段代码需要 20 秒才能运行。然后我决定像这样关闭渠道工厂:

    [TestMethod]
    [Timeout(2000)]
    public void ApiClientTest()
    {
        bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false;
        Api apiService = new ApiTestService();
        var clientService = new ClientTestService();

        ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService));
        ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService));

        //To let us know the services were successfully opened
        clientHost.Opened += (s, e) => ClientSuccessSet = true;
        apiHost.Opened += (s, e) => ApiSuccessSet = true;
        clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName);
        apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName);
        clientHost.BeginOpen(OnOpen, clientHost);
        apiHost.BeginOpen(OnOpen, apiHost);


        //This allows both services to be open for communication.
        while (!ApiSuccessSet || !ClientSuccessSet)
            Thread.Yield();


        EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName);
        EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName);

        InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback());
        var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint);
        var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint);
        var ClientChannel = ClientChannelFactory.CreateChannel();
        var ApiChannel = ApiChannelFactory.CreateChannel();


        ClientChannelFactory.Close();
        ApiChannelFactory.Close();
        clientHost.Close();
        apiHost.Close();
    }

这让我相信处理客户端的实例上下文需要很长时间。

我怀疑有 3 种方法可以更好地处理此解决方案。

第一个是在管理结束会话的客户端上创建一个函数。这样,您可以在服务计划关闭之前调用该方法,这将加快关闭时间。

二是在连接关闭时异步关闭并做其他处理。

第三是在何时关闭连接(特别是如果您同时控制客户端和服务)对客户端进行编程,以便客户端可以自行终止会话并且服务可以优雅快速地关闭。

于 2014-07-07T20:37:44.450 回答