WCF TCP客户端 - 如何使用它们的基本指南?

10

我有一个WCF服务,想使用TCP绑定连接它。这很好,但是你应该如何处理客户端呢?我注意到如果你每次调用都创建一个新的客户端,它不会重用通道并且会留下一堆TCP连接直到它们超时。

创建一个客户端,调用其中的方法,然后关闭它是正常使用吗?

如果你想重新使用连接怎么办?有什么限制吗?你能从不同的线程中同时发起多个调用吗?如果不能,是否必须自己进行连接池管理?在重用连接时,是否需要在发起调用之前检查连接状态并在连接失败时清理它?

2个回答

17

这里有很多问题需要一起处理,情况有些复杂。创建客户端时,你可以通过服务引用获得从ClientBase<ServiceContract>派生的类,或者使用ChannelFactory<ServiceContract>手动创建通道(前一种情况在内部使用了ChannelFactory)。

这与你的问题有何关联?首先让我们看看真正的TCP连接。当你定义NetTcpBinding时,你可以设置它的MaxConnections属性(默认值为10)。该属性定义了池化连接的数量。这意味着,如果你向服务器创建客户端通道并关闭通道,则连接不会立即终止。它会保持在池中,直到被同一服务器上另一个打开的客户端通道使用,或者直到其空闲超时到期。你可以打开服务器允许的任意数量的连接,但只有由MaxConnections定义的数量将在关闭相关的客户端通道时被池化。其他连接将立即终止。如果创建了CustomBinding,则可以直接使用TCP传输,在那里你也可以控制空闲超时时间(我认为默认值为2分钟)。只要相关的ChannelFactory未被销毁,连接就会被保留在池中 = 每个应用程序使用一个ChannelFactoryClientBase在内部执行此操作)。

现在让我们谈谈通道本身,因为它与你的其他问题有关。WCF有会话型和非会话型通道。 TcpTransportChannel是会话型的。这意味着,一旦你打开通道,就创建了一个会话。会话表示单个客户端代理的所有请求默认情况下始终由同一服务实例处理(按会话实例)。但该实例默认为单线程。这意味着,你可以有多个线程使用同一个代理,但服务将按顺序处理请求。如果你想让服务同时处理多个请求,必须使用[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]标记它。一旦你这样做,你就需要负责服务中的线程安全处理(多个线程访问同一个服务实例)。

Sessionful通道有一个很大的缺点。服务上的任何故障或异常都将中断通道,并且通常在您尝试再次使用该通道后才会得知(异常显示通道处于故障状态,无法使用)。您必须始终正确处理这些情况,并且一旦不想使用它们或发生故障时必须正确关闭通道/代理或中止它们。故障通道无法修复-必须中止它并创建新的代理/通道。如果不这样做,连接是否返回池中我不确定。

重用代理/通道取决于您正在构建的应用程序类型。我绝对不会在Web应用程序中的多个请求之间重用代理/通道,但是在WinForm或WPF应用程序中重用绝对可以。

编辑:

是的,ClientBase在内部使用了ChannelFactoryChannelFactory的使用方式随时间而变化。 在.NET 3.0中,为每个ClientBase实例创建了工厂。自.NET 3.5以来,WCF在内部使用MRU高速缓存(最近使用)高速缓存32个最近使用的工厂。要利用此缓存,您必须使用没有参数或带有endpointConfigurationNameremoteAddress / EndpointAddress的代理构造函数。您不应该在代码中创建端点-这些代理不使用缓存。关于该主题的更多信息请参见此处


Ladislav,如果一个WCF服务被定义为SessionMode = NotAllowed,这是否意味着该服务的客户端服务代理不需要关闭? - Dan Ling
@Otter:如果服务定义为 SessionMode=NotAllowed,则您不能使用任何包括 net.tcp 在内的会话通道。您应该始终关闭或中止代理。它实现了 IDisposable 接口 - 一旦您看到它,就应该始终处理它。 - Ladislav Mrnka
ClientBase使用一个共同的ChannelFactory吗?这是在所有ClientBase实例中都通用的吗?当我调用ClientBase.Open()时,这意味着什么?它会从工厂创建一个通道并打开它吗? - RandomEngy
我添加了一些细节。实际上,当您在ClientBase上调用Open时,我不确定会发生什么-没有必要调用它,但是该方法可用,因为ClientBase实现了要求此方法的ICommunicationObject - Ladislav Mrnka
没有通道缓存。每个代理的通道都是唯一的。只有工厂会被重用。我很确定你可以在不调用Open的情况下在代理上调用方法。我几分钟前就这样做了,所以看到它不起作用的示例细节会很有趣。通过在代码中定义终结点,我真正意思是绑定。 - Ladislav Mrnka
显示剩余2条评论

0
你在客户端关闭了服务代理吗?
IService service = channelFactory.CreateChannel();

service.DoStuff();

((IContextChannel) service).Close();

这适用于所有的WCF客户端,无论绑定是否为TCP。

更多信息请参见:http://msdn.microsoft.com/en-us/library/aa355056.aspx


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接