none
关于wcf连接问题 RRS feed

  • 问题

  •   我在服务器建立好wcf服务,

    然后在客户端添加服务引用: ServiceReference1.Service1Client service = new cbClient.ServiceReference1.Service1Client(); 

    客户端一直用service 调用服务器端的方法。

    我想问一下,是每次跟服务器端通讯就新建一个连接?还是客户端不关闭就一直跟服务器端保持连接? 哪一种选择更好?(我的系统在线人数是80-100人,有局域网有internet。)

    另外,如果用netTcpBinding 绑定,那么客户长时间不用就会信道出错,而使用wsHttpBinding就没有这个问题。

    还有我想开通wcf的双工模式,双工模式是不是对网络更高,更不稳定?

    2013年1月4日 1:55

答案

  • 最好一直保持,直到不可用时,再重新建立连接。

    如果用netTcpBinding时,有个 inactivetimeout 可以设置,你可以设置为更长点,或者在超时前发一次请求,或者还是向上面那样,不可用时,再重新建立连接。

    双工的话,用 netTcpBinding 最合适,基于http的dual绑定无法穿透NAT。

    关于直到不可用时,重新建立连接,推荐你写个单例的模板类,类似如下,通过try catch 来破获到CommnutionException后重新建立通道:

        public class WcfClientBase<TChannel> where TChannel : class
        {
            private static object _channelLock = new object();
            private static ChannelFactory<TChannel> _factory;
            private static TChannel _channel;
            private string _endpoint;
            private string _bindingConfig;
            public WcfClientBase(string endpoint, string bindingConfig)
            {
                _endpoint = endpoint;
                _bindingConfig = bindingConfig;
                if (_channel != null)
                {
                    try
                    {
                        ((IChannel)_channel).Close(TimeSpan.FromMilliseconds(10000));
                    }
                    catch
                    {
                        ((IChannel)_channel).Abort();
                    }
                }
                if (_factory != null)
                {
                    try
                    {
                        _factory.Close(TimeSpan.FromMilliseconds(10000));
                    }
                    catch
                    {
                        _factory.Abort();
                    }
                }
                _channel = null;
                _factory = null;
            }
            public TChannel Channel
            {
                get
                {
                    TChannel localChannel = _channel;
                    if (localChannel == null)
                    {
                        lock (_channelLock)
                        {
                            if (_channel != null)
                                return _channel;
                            if (_factory == null)
                            {
                                try
                                {
                                    EndpointAddress remoteNodeEndPointAddress = new EndpointAddress(_endpoint);
                                    _factory = new ChannelFactory<TChannel>(_bindingConfig, remoteNodeEndPointAddress);
                                }
                                catch
                                {
                                    throw;
                                }
                            }
                            _channel = _factory.CreateChannel();
                            //Note:  VERY important to call open here, fix from prior releases where open was not called,
                            //resulting in spotty client-side bottleneck when clients run many threads.
                            ((IChannel)_channel).Open();
                            return _channel;
                        }
                    }
                    return localChannel;
                }
                set
                {
                    lock (_channelLock)
                    {
                        if (_channel != null && ((IChannel)_channel).State != CommunicationState.Opened)
                        {
                            ((IChannel)_channel).Abort();
                            _channel = null;
                            if (_factory != null && _factory.State != CommunicationState.Opened)
                            {
                                _factory.Abort();
                                _factory = null;
                            }
                        }
                    }
                }
            }
            public void Open()
            {
                TChannel localChannel = this.Channel;
            }
            public void Close()
            {
                lock (_channelLock)
                {
                    if (_channel != null)
                    {
                        try
                        {
                            ((IChannel)_channel).Close();
                        }
                        catch
                        {
                            ((IChannel)_channel).Abort();
                        }
                    }
                    if (_factory != null)
                    {
                        try
                        {
                            _factory.Close();
                        }
                        catch
                        {
                            _factory.Abort();
                        }
                    }
                    _channel = null;
                    _factory = null;
                }
            }
        }

    上面的代码可以根据你的场景来做些调整,比如我会把构造函数中的断开连接的代码注释掉来用。上面代码是参考StockTrader中的源码来实现的,可能的使用方法:

        public class CacheServiceClient : WcfClientBase<ICacheService>, ICacheService
        {
            public CacheServiceClient(string endpoint, string bindingConfig)
                : base(endpoint, bindingConfig)
            {
            }
            #region ICacheService 成员
            public void Add(string cacheManagerName, string key, string value)
            {
                try
                {
                    this.Channel.Add(cacheManagerName, key, value);
                }
                catch
                {
                    this.Channel = null;
                    throw;
                }
            }
            
            #endregion
        }


    2013年1月4日 3:52