WCF TCP 客户端 - 如何使用它们的基本指南?
我有一个 WCF 服务并希望使用 TCP 绑定连接到它。这一切都很好,但是你应该如何处理客户呢?我注意到,如果您为每个调用创建一个新客户端,它不会重新使用该通道,并会留下一堆 TCP 连接,直到超时。
创建客户端,调用其方法,然后关闭它是正常使用吗?
如果您想重新使用该连接怎么办?对此有何限制?可以从不同线程同时调用吗?如果不能,是否必须自己进行连接池?当重新使用连接时,是否必须在调用之前检查连接状态并在出现故障时进行清理?
I've got a WCF service and want to connect to it using a TCP binding. This is all well and good, but how are you supposed to handle the clients? I've noticed that if you create a new client for each call it doesn't re-use the channel and leaves around a bunch of TCP connections until they time out.
Is it normal use to create a client, call a method on it, then close it?
What if you want to re-use the connection? What are the limitations on that? Can you make simultaneous calls from different threads? If you can't, do you have to do your own connection pooling? And when re-using the connection, do you have to check the connection state before making calls and clean it up if it's faulted?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
嗯,这是很多问题,而且情况确实有点复杂。创建客户端时,您可以通过服务引用并获取从
ClientBase
派生的类来完成,也可以使用ChannelFactory
并手动创建通道(前一种情况在内部使用 ChannelFactory)。这与你的问题有何关系?我们首先看一下真实的 TCP 连接。定义 NetTcpBinding 时,您可以设置其 MaxConnections 属性(默认值为 10)。该属性定义池连接的数量。这意味着如果您创建到服务器的客户端通道并关闭该通道,连接不会立即终止。它在池中保持打开状态,直到被同一服务器的另一个打开的客户端通道使用或直到其空闲超时到期。您可以打开服务器允许的任意数量的连接,但一旦您关闭相关的客户端通道,只有
MaxConnections
定义的数量才会被池化。其他连接将立即终止。如果您创建 CustomBinding,您可以直接使用 TCP 传输,您还可以控制空闲超时(我认为默认值为 2 分钟)。只要相关的ChannelFactory
不被破坏,连接就会被池化 = 每个应用程序使用一个ChannelFactory
(ClientBase
在内部执行)。现在我们来谈谈频道本身,因为它与您的其他问题有关。 WCF 区分会话通道和无会话通道。
TcpTransportChannel
是会话式的。这意味着一旦您打开频道,您就创建了一个会话。会话意味着来自单个客户端代理的所有请求默认情况下始终由同一服务实例(每个会话实例)提供服务。但该实例默认是单线程的。这意味着您可以有多个线程使用同一代理,但服务将按顺序处理请求。如果您希望服务同时处理多个请求,则必须使用[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple]
进行标记。一旦您这样做,您就负责服务中的线程安全处理(多个线程访问 )。会话通道有一个很大的缺点,服务上的任何故障或异常都会破坏通道,并且在您尝试再次使用该通道后通常会知道这一点(例外情况是通道处于故障状态且无法恢复 您必须始终正确处理这些情况,并且在不想使用通道/代理时必须正确关闭它们,或者一旦出现故障就中止它们 - 必须中止它并且必须创建一个。新的代理/通道。如果您不这样做,我不确定连接是否会返回到池中,
这取决于您正在构建的应用程序的类型。 Web 应用程序,但在 WinForm 或 WPF 应用程序中重用是绝对可以的。
编辑:
是的
ClientBase
在内部使用ChannelFactory
。ChannelFactory
的使用方式随着时间的推移而发生了变化。在 .NET 3.0 中,为每个 ClientBase 实例创建工厂。由于 .NET 3.5 WCF 使用内部 MRU 缓存(最近使用的),它最多可缓存 32 个最近使用的工厂。要利用此缓存,您必须使用不带参数或带有endpointConfigurationName
和remoteAddress
/EndpointAddress
的代理构造函数。您不得在代码中创建端点 - 这些代理不使用缓存。有关该主题的更多信息是 此处。Well this is a lot of questions together and the situation is really little bit complicated. When you create a client you can do it either via service reference and get class derived from
ClientBase<ServiceContract>
or you can useChannelFactory<ServiceContract>
and create channels manually (the former case uses the ChannelFactory internally).How this relates to your question? Lets first look at real TCP connection. When you define
NetTcpBinding
you can set itsMaxConnections
property (default is 10). This property defines the number of pooled connection. It means that if you create client channel to the server and close the channel the connection is not terminated immediately. It remains opened in the pool until it is used by another opened client channel to the same server or until its idle timeout expires. You can open as many connections as the server allows you but only number defined byMaxConnections
will be pooled once you close related client channels. Other connections will be terminated immediately. If you createCustomBinding
you can use TCP transport directly where you can also control idle timeout (I think default is 2 minutes). Connections are pooled as long as the relatedChannelFactory
is not destroyed = use oneChannelFactory
per application (ClientBase
do it internally).Now lets talk about channel itself because it is related to your other questions. WCF differs sessionfull and sessionless channels.
TcpTransportChannel
is sessionfull. It means that once you open the channel you create a session. Session means that all requests from the single client proxy are by default always served by the same service instance (per session instancing). But the instance is by default single threaded. It means that you can have multiple threads using the same proxy but the service will handle requests in a sequential order. If you want your service to process multiple request simultaneously you must mark it with[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple]
. Once you do it you are responsible for thread safe processing in the service (multiple threads accessing same service instance).Sessionful channels have one big disadvantage. Any failure or exception on the service will break the channel and you will usually know about it after you try to use the channel again (exception saying that channel is in faulted state and cannot be used). You must always correctly handle these situations and you must correctly close channels/proxies once you don't want to use them or abort them once they are faulted. Faulted channel cannot be repaired - it must be aborted and you must create a new proxy/channel. I'm not sure if connections are returned to pool if you don't do that.
Reusing proxy/channel depends on the type of application you are building. I would definitely not reuse proxy/channel among multiple requests in web application but reusing is absolutely ok in WinForm or WPF application.
Edit:
Yes
ClientBase
usesChannelFactory
internally. The way how theChannelFactory
is used has changed over time. In .NET 3.0 the factory was created for eachClientBase
instance. Since .NET 3.5 WCF uses internally MRU cache (Most recently used) which caches up to 32 lastly used factories. To take advantage of this caching you must use proxy constructor without parameters or withendpointConfigurationName
andremoteAddress
/EndpointAddress
. You mustn't create endpoint in the code - these proxies doesn't use the cache. More about the topic is here.您是否关闭客户端的服务代理?
这适用于所有 WCF 客户端,无论绑定是否为 TCP。
有关详细信息,请参阅:http://msdn.microsoft.com/en-us /library/aa355056.aspx
Are you closing your service proxies on the client side?
This applies to all WCF clients, regardless of whether the binding is TCP or not.
For more information, see: http://msdn.microsoft.com/en-us/library/aa355056.aspx