TransferMode = Streamed时耗尽连接

时间:2017-05-09 10:09:21

标签: c# .net wcf

我有一个简单的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个请求正在排队。

1 个答案:

答案 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
}