WCF ServiceHost.Close() 延迟

Posted

技术标签:

【中文标题】WCF ServiceHost.Close() 延迟【英文标题】:WCF ServiceHost.Close() Delay 【发布时间】:2010-11-04 17:52:12 【问题描述】:

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

另一方面,Abort() 几乎是即时的,我很想用它来代替。

【问题讨论】:

【参考方案1】:

可能是这样。 docs 声明

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

Close() 有一个重载,它需要一个 TimeSpan(如果超过时间跨度,throws

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

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

为了方便,我可以看到 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

【讨论】:

我相信你可以重新安排,这样所有的“s.Close()”都会先发出,然后在信号量上等待。【参考方案5】:

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

[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 种方法可以更好地处理此解决方案。

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

第二种是异步关闭,在连接关闭的同时做其他处理。

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

【讨论】:

以上是关于WCF ServiceHost.Close() 延迟的主要内容,如果未能解决你的问题,请参考以下文章

动态演示频域采样与时域周期延拓现象

Overture 钢琴插件延音问题

matlab中如何对已知函数进行周期延拓

Matlab使用延拓求解 BVP

网络分流器|运营商光纤延距解决方案

网络分流器|运营商光纤延距解决方案