我有一个简单的REST服务,并通过WebChannelFactory
通过WCF调用它。
当我将绑定设置为使用TransferMode.Streamed
时,连接似乎没有被重用,并且在几次请求之后(通常是ServicePointManager.DefaultConnectionLimit
,但有时候还有一些),我的连接耗尽(请求调用挂起,然后我得到超时异常)。
[ServiceContract]
public interface IInviteAPI {
[OperationContract]
[WebGet(UriTemplate = "invites/{id}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
Invite GetInvite(string id);
}
[STAThread]
static int Main(string[] args) {
ServicePointManager.DefaultConnectionLimit = 16; // make a larger default
WebHttpBinding binding = new WebHttpBinding();
binding.TransferMode = TransferMode.Streamed;
try {
WebChannelFactory<IInviteAPI> factory = new WebChannelFactory<IInviteAPI>(binding, new Uri("http://example.com/invite"));
IInviteAPI channel = factory.CreateChannel();
for (int i = 0; i < 100; i++) {
Invite data = channel.GetInvite("160"); // fails on i==16
}
((IChannel)channel).Close();
}
catch (Exception ex) {
Debug.WriteLine(ex);
}
return 0;
}
System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9969999.
网上有很多关于不关闭频道的帖子 - 这不是问题,因为我只是在同一频道上多次发出相同的请求。
binding.TransferMode = TransferMode.Streamed;
行,则效果非常好。我也可以创建和关闭循环内的通道,它有同样的问题
for (int i = 0; i < 100; i++) {
IInviteAPI channel = factory.CreateChannel();
Invite data = channel.GetInvite("160"); // fails on i==20
((IChannel)channel).Close();
}
GC.Collect()
,它确实有用!!经过.Net代码的详细跟踪后,这似乎是因为ServicePoint
仅在ServicePointManager
中使用弱引用。调用GC.Collect
然后完成ServicePoint
,并关闭所有当前连接。我有什么遗失的吗?如何保持TransferMode.Streamed
并能够使用合理的ServicePointManager.DefaultConnectionLimit
多次致电服务?
(我需要TransferMode.Streamed
,因为该服务的其他调用用于传输大量1GB的数据档案。
更新:
如果我运行netstat -nb,我可以看到在ESTABLISHED状态下有16个连接到服务器。大约30秒后,它们会更改为CLOSE_WAIT(可能是服务器关闭了空闲连接),但是在此之后这些CLOSE_WAIT连接永远不会消失,无论我设置超时有多大。
这似乎是.Net中的一个错误:连接应该被重用,但不是。第17个请求正在排队。
答案 0 :(得分:0)
我知道对WCF配置默认限制,并发性和可伸缩性的并发入站连接有20个限制。
您可以删除并发连接限制或:
for (int i = 0; i < 100; i++) {
Invite data = channel.GetInvite("160");
Thread.Sleep(1000); // prevent to concurrency connection to wcf service
}