none
请教一个WCF服务关闭后再开启的调用问题 RRS feed

  • 问题

  • 各位大侠好:

    现在我有这样一个需求, WCF服务采用单调服务, 客户端不停的调用WCF服务

    需要当WCF服务关闭后再打开时, 客户端的代理仍然有效.

    我现在是这样做的, 在客户端调用WCF服务的错误处理中重新创建代理, 这样的话, 只要服务端开启, 总会成功的创建一个可以成功用于通信的代理.

    不知这样是否合理, 如果有更合理的做法, 希望大侠分享一下~

    try
                {
                        this.Proxy.SendData(this.SendDatas);
                }
                catch (CommunicationException ex)
                {
                    ICommunicationObject CommunicationObject = this.Proxy as ICommunicationObject;
                    if (CommunicationObject != null)
                    {
                        CommunicationObject.Abort();
                    }
                    this.Proxy = new Monitor.TransformDataService.TransformDataClient();
                }
                catch (TimeoutException ex)
                {
                    ICommunicationObject CommunicationObject = this.Proxy as ICommunicationObject;
                    if (CommunicationObject != null)
                    {
                        CommunicationObject.Abort();
                    }
                    this.Proxy = new Monitor.TransformDataService.TransformDataClient();
                }
                catch (Exception ex)
                {
                    ICommunicationObject CommunicationObject = this.Proxy as ICommunicationObject;
                    if (CommunicationObject != null)
                    {
                        if (CommunicationObject.State != CommunicationState.Faulted)
                        {
                            CommunicationObject.Close();
                        }
                    }
                    this.Proxy = new Monitor.TransformDataService.TransformDataClient();
                }

    2011年4月15日 5:17

答案

全部回复

  • 我看行.
    2011年4月15日 7:36
  • 可以的。

    但是为什么不每次新建一个呢?提高并发性。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月16日 15:50
  • 可以的。

    但是为什么不每次新建一个呢?提高并发性。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。

    如果每次新建一个,事实上性能是最低的.因为通道只有一个,你每次Open的时候,它都会先lock住,一次只允许一个连接操作.
    2011年4月18日 2:45
  • 这样可以保证每次能获得可以正常工作的 客户端代理类实例。

    服务端如果关闭,客户端代理会捕获异常的,

    按照你的代码,会重新实例化一个代理实例。

    可以工作

     


    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
     

    老徐的网站】:http://www.frankxulei.com/

    微软WCF中文技术论坛
    微软WCF英文技术论坛

    Windows Azure中文技术论坛

    • 已标记为答案 Tale Xu 2011年4月20日 2:49
    2011年4月18日 10:12
    版主

  • 可以的。

    但是为什么不每次新建一个呢?提高并发性。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。

    如果每次新建一个,事实上性能是最低的.因为通道只有一个,你每次Open的时候,它都会先lock住,一次只允许一个连接操作.
    不知这个结论从何而来?
    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月18日 14:42

  • 可以的。

    但是为什么不每次新建一个呢?提高并发性。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。

    如果每次新建一个,事实上性能是最低的.因为通道只有一个,你每次Open的时候,它都会先lock住,一次只允许一个连接操作.
    不知这个结论从何而来?
    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。


    从负载测试中来,从通道模型中来.

    有时间,请下载StockTrader示例项目,阅读他们的wcf client实现模式.

    2011年4月20日 2:17
  • 举个例子,新建10个Client,并发调用实例模式是PerCall的服务的同一个操作(操作之间没有共享任何数据),每个操作耗时5秒,意思是这10个操作需要50秒(忽略连接时间)才能完成?
    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月20日 2:29
  • 按照这个思路, 我又新建了个HitTest线程来负责代理的检测, 这样界面上的效率会更高

    谢谢各位~

    2011年4月20日 2:49
  • 举个例子,新建10个Client,并发调用实例模式是PerCall的服务的同一个操作(操作之间没有共享任何数据),每个操作耗时5秒,意思是这10个操作需要50秒(忽略连接时间)才能完成?
    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。


    从理论上讲,如果你这5秒内占用了全部带宽,10个操作就需要50秒.

    如果你只是在服务端休眠5秒,那么事实上连接被空闲出来了,其它client可以在这5妙内执行它们的操作.

    这就是我们经常的说的要限流.当然,这里的推论的前提条件是服务器限制每客户端的最大连接数为1,通常的设置是2.

    话说回来,就算服务器允许客户端有多个连接,每次调用仍然受带宽限制.

     

    同时,你说的忽略连接的前提条件就与楼主的提问相违背.因为当一个client出错后,其它client都需要重新建立连接,

    那么它们都需要对同一个http connection进行操作,有的执行 Abort,有的执行 Open,有的执行Close,也就是多个

    并发操作需要修改 tcp connection 的状态,这就涉及到同步,因为你只有一个状态值,你需要它对所有调用都是一致的.

    2011年4月20日 3:57
  • 服务器限制每客户端的最大连接数为1,通常的设置是2.

    请问这个数据是从哪得来的?

    我后面讨论的是针对你的这句:“一次只允许一个连接操作.”,并不是楼主的提问。

    针对你这个回复,我认为限流和带宽并没关系,甚至限流里的配置都没有可以跟带宽有关的东西。

    另外,楼主以及我们的回复都没有对绑定作出假设,也就不能局限于Http相关的绑定。

    我只想针对并发性做讨论,是不是真的一次只允许一个连接操作。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月20日 4:36
  • 服务器限制每客户端的最大连接数为1,通常的设置是2.

    请问这个数据是从哪得来的?

    我后面讨论的是针对你的这句:“一次只允许一个连接操作.”,并不是楼主的提问。

    针对你这个回复,我认为限流和带宽并没关系,甚至限流里的配置都没有可以跟带宽有关的东西。

    另外,楼主以及我们的回复都没有对绑定作出假设,也就不能局限于Http相关的绑定。

    我只想针对并发性做讨论,是不是真的一次只允许一个连接操作。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。


    HTTP连接数限制,这个可以从bing上搜索下嘛.

    我指的限流,不是你认为的wcf的配置,而是所有网际通讯协议.

    "一次只允许一个连接操作"是指的"打开" ,"关闭"通道.

    不知道你有没有作过测试,建立一个通道,和每次新建一个通道在客户端调用性能上真的差距非常大.

    建议你自己做负载测试,类似为什么wcf并发调用的时候这么慢之类的问题,我们的建议都是设置一个 static Channel,全局共享该Channel.

    2011年4月20日 7:14
  • HTTP连接数限制,在1.1规范中是建议不超过2个连接,.Net由ServicePointManager.DefaultPersistentConnectionLimit这个常量来定义,这我知道。

    且这个连接限制是可以修改的。

    但是TCP连接有这个限制?“服务器限制每客户端最大连接数为1,通常设置为2的限制”,不知道这个结论从何而来。

    况且如果使用的是Http相关绑定,只要非Session的通道,服务没理由去关心是否是同一个客户端发起的不同调用。

    每次新建一个通道自然比共享一个通道慢,这个我从不怀疑,建立连接时很耗时的,学过计算机网络的人都有这个概念。

    但是,全局共享Channel必然不是最佳方案,如果是,数据库连接池就没必要设计出来。而且全局共享Channle不会有多线程的风险?我表示怀疑。

    10个通道一起发送数据,必然比一个通道快,连接池应该是最好的方式,就是增加了复杂性。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月20日 8:05
  • HTTP连接数限制,在1.1规范中是建议不超过2个连接,.Net由ServicePointManager.DefaultPersistentConnectionLimit这个常量来定义,这我知道。

    且这个连接限制是可以修改的。

    但是TCP连接有这个限制?“服务器限制每客户端最大连接数为1,通常设置为2的限制”,不知道这个结论从何而来。

    况且如果使用的是Http相关绑定,只要非Session的通道,服务没理由去关心是否是同一个客户端发起的不同调用。

    每次新建一个通道自然比共享一个通道慢,这个我从不怀疑,建立连接时很耗时的,学过计算机网络的人都有这个概念。

    但是,全局共享Channel必然不是最佳方案,如果是,数据库连接池就没必要设计出来。而且全局共享Channle不会有多线程的风险?我表示怀疑。

    10个通道一起发送数据,必然比一个通道快,连接池应该是最好的方式,就是增加了复杂性。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。


    MS真的不推荐你做个通道连接池,因为WCF底层已经做了。而且MS真的推荐你对每个 ip+port 用一个Channel,这在StockTrader示例项目里是做了注释的。

    另外,你可以用netstat查看下你本地的端口数和服务器的端口数,连接不是只关注IP,它还有PORT,服务器有一个IP+PORT,请问你建立10个通道后,你的客户端使用了

    几个PORT?当你打开10个数据库连接并查询数据的时候,请问你的客户端使用了几个PORT?

    你跟我在这里较劲,还不如你自己做负载测试试验下效果,10个通道真的没有1个通道快。

    摘录StockTrader配置项中的一项说明:

    NumberClientChannels 1 The number of WCF client channels created per service host. Typically need just one--even in high-traffic scenarios.
    2011年4月20日 8:32
  • 按你的要求做了:
      TCP    192.168.1.204:23439    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23440    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23441    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23442    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23443    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23444    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23445    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23446    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23447    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23451    192.168.1.222:8502     ESTABLISHED     7920
    开的10个client,并发调用,客户端用了10个Port,这个和你说的似乎不一致。

    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月20日 9:49
  • 你们讨论的很激烈,蛮好的。

    这样利于弄明白问题。

    但是任何结论,都是有前提条件的。

    所以大家没必要非说对方的错,即使自己的观点正确,那么最好加上限制条件。

    这样方便交流,讨论


    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
     

    老徐的网站】:http://www.frankxulei.com/

    微软WCF中文技术论坛
    微软WCF英文技术论坛

    Windows Azure中文技术论坛

    2011年4月20日 10:06
    版主
  • 哈哈,如果我的语气不好,我道歉。

    老徐你对客户端的并发性是什么观点?


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月20日 10:52
  • 我晚上做了实验,结果很奇特,在客户端服务端配置不变的情况下,使用TCP绑定(服务,PerCall,单线程),使用异步发起同步调用,发现能干扰结果因素很多。

    甚至在有些情况下共享通道和每次打开一个耗时差不多(连接池最小线程数量的配置x10),下次考虑采用异步调用试试看。

    不过总的情况还是共享通道比每次打开一个快,这个一直都没异议。

    结果证实了共享的通道越多,速度越快,我的实验里面共享10个通道,比共享1个通道快,最优的测试中也快了6%。

    不过使用池未必会加快速度,因为涉及到池的设计,这里面如果有锁的开销,会迅速增加系统开销,我简单实现了一个发现效果很差。


    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月20日 14:25
  • 按你的要求做了:
      TCP    192.168.1.204:23439    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23440    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23441    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23442    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23443    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23444    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23445    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23446    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23447    192.168.1.222:8502     ESTABLISHED     7920
      TCP    192.168.1.204:23451    192.168.1.222:8502     ESTABLISHED     7920
    开的10个client,并发调用,客户端用了10个Port,这个和你说的似乎不一致。

    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。


    我给你提个测试建议:

    http绑定:

    1,一个 static IChannel,并发调用IChannel上的方法,然后通过 netstat 查看本地端口的变化;

    2,10个 IChannel(在同一个应用程序域中),并发调用每个 IChannel上的方法(注意每个IChannel实例都要能够被并发调用),然后通过 netstat 查看本地端口的变化;

     

    然后换成tcp绑定再测试一次。最好使用微软的负载测试工具,

    测试客户端的写法,可以使用StockTrader的 WSClient 。

    最后,根据你对http和tcp的认识总结你的测试结果,加深你对http和tcp的相互关系的认识。


    2011年4月21日 3:26
  • 不如你做了把结果发出来,或者把你的结论总结发出来,我学习一下。
    快乐在于能够长时间的为自己认为值得的事情努力工作,不管它是什么。
    2011年4月21日 3:33