我有一个简单的 WCF 双工 TCP 服务,我试图以编程方式停止它。如果我没有任何连接的用户,ServiceHost.Close() 非常快,但如果我什至有一个连接的用户,我发现 Close() 函数需要相当长的时间,有时 > 30 秒。这是通常的行为吗?
另一方面, Abort() 几乎是瞬时的,我很想改用它。
可能是。文档指出_
Close 方法允许在返回之前完成任何未完成的工作。例如,完成发送任何缓冲的消息。
有一个过载Close()
需要一个TimeSpan
(throws
如果超过时间跨度)
Abort()
看起来像是立即停止 WCF 主机的最佳方法。
确保您正在关闭客户端连接,如下所示:
var channel = factory.CreateChannel();
var channel.DoSomethingForMe();
(channel as ICommunicationObject).Close();
如果您不在通道上执行此 Close(),则服务器上的 Close() 会等待非常非常长的时间,即使您指定了很短的超时时间也是如此。
如果您可以终止任何正在进行的服务调用,那么 Abort() 就是要走的路。Close() 是关闭服务的礼貌方式。
为了权宜之计,我可以看到 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
我也注意到了这个问题。我的代码最初看起来像这样:
[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 种方法可以更好地处理此解决方案。
第一个是在管理结束会话的客户端上创建一个函数。这样,您可以在服务计划关闭之前调用该方法,这将加快关闭时间。
二是在连接关闭时异步关闭并做其他处理。
第三是在何时关闭连接(特别是如果您同时控制客户端和服务)对客户端进行编程,以便客户端可以自行终止会话并且服务可以优雅快速地关闭。