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

发布于 2024-11-11 21:16:17 字数 237 浏览 1 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

誰認得朕 2024-11-18 21:16:17

嗯,这是很多问题,而且情况确实有点复杂。创建客户端时,您可以通过服务引用并获取从 ClientBase 派生的类来完成,也可以使用 ChannelFactory 并手动创建通道(前一种情况在内部使用 ChannelFactory)。

这与你的问题有何关系?我们首先看一下真实的 TCP 连接。定义 NetTcpBinding 时,您可以设置其 MaxConnections 属性(默认值为 10)。该属性定义池连接的数量。这意味着如果您创建到服务器的客户端通道并关闭该通道,连接不会立即终止。它在池中保持打开状态,直到被同一服务器的另一个打开的客户端通道使用或直到其空闲超时到期。您可以打开服务器允许的任意数量的连接,但一旦您关闭相关的客户端通道,只有 MaxConnections 定义的数量才会被池化。其他连接将立即终止。如果您创建 CustomBinding,您可以直接使用 TCP 传输,您还可以控制空闲超时(我认为默认值为 2 分钟)。只要相关的 ChannelFactory 不被破坏,连接就会被池化 = 每个应用程序使用一个 ChannelFactoryClientBase 在内部执行)。

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

会话通道有一个很大的缺点,服务上的任何故障或异常都会破坏通道,并且在您尝试再次使用该通道后通常会知道这一点(例外情况是通道处于故障状态且无法恢复 您必须始终正确处理这些情况,并且在不想使用通道/代理时必须正确关闭它们,或者一旦出现故障就中止它们 - 必须中止它并且必须创建一个。新的代理/通道。如果您不这样做,我不确定连接是否会返回到池中,

这取决于您正在构建的应用程序的类型。 Web 应用程序,但在 WinForm 或 WPF 应用程序中重用是绝对可以的。

编辑:

是的 ClientBase 在内部使用 ChannelFactoryChannelFactory 的使用方式随着时间的推移而发生了变化。在 .NET 3.0 中,为每个 ClientBase 实例创建工厂。由于 .NET 3.5 WCF 使用内部 MRU 缓存(最近使用的),它最多可缓存 32 个最近使用的工厂。要利用此缓存,您必须使用不带参数或带有 endpointConfigurationNameremoteAddress / 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 use ChannelFactory<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 its MaxConnections 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 by MaxConnections will be pooled once you close related client channels. Other connections will be terminated immediately. If you create CustomBinding 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 related ChannelFactory is not destroyed = use one ChannelFactory 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 uses ChannelFactory internally. The way how the ChannelFactory is used has changed over time. In .NET 3.0 the factory was created for each ClientBase 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 with endpointConfigurationName and remoteAddress / EndpointAddress. You mustn't create endpoint in the code - these proxies doesn't use the cache. More about the topic is here.

南巷近海 2024-11-18 21:16:17

您是否关闭客户端的服务代理?

IService service = channelFactory.CreateChannel();

service.DoStuff();

((IContextChannel) service).Close();

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

有关详细信息,请参阅:http://msdn.microsoft.com/en-us /library/aa355056.aspx

Are you closing your service proxies on the client side?

IService service = channelFactory.CreateChannel();

service.DoStuff();

((IContextChannel) service).Close();

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文