How can I make Named Pipe binding reconnect automatically in WCF

后端 未结 3 1435
走了就别回头了
走了就别回头了 2020-12-13 11:21

I\'m writing a service that will only get calls from the local host. Performance is important so I thought I\'d try the NetNamedPipeBinding instead of NetTcpBinding and see

3条回答
  •  别那么骄傲
    2020-12-13 12:03

    I haven't used NetNamedPipes in WCF but I spent more time than I cared to learning the timeout values for NetTcp. I use the following configs for my NetTcpBindings and had good luck with the connection staying active.

    Server:

    
        
        
    
    

    Client:

    
        
        
    
    

    The important settings that I spent the most time on are the sendTimeout and receiveTimeout. If your receiveTimeout is the same or less than your send, the channel will drop once that timeout is reached. If the receive is higher and the send is above a threshold, the channel will fire a transport level keepalive. From my tests, the sendTimeout threshold is 30 seconds. Anything less than that and the keepalives aren't sent.

    Additionally, I have a timer based keepalive call that I execute every minute to try and ensure the channel is up and working well. The call is simply to a boolean return member:

    [OperationContract(IsOneWay = false, IsInitiating = false, IsTerminating = false)]
    bool KeepAlive();
    
    public bool KeepAlive()
    {
        return true;
    }
    

    You can also grab the channel events (if you get them at the right time) and reopen the connection if something bad happens:

    InstanceContext site = new InstanceContext(this);
    _proxy = new MyServiceChannel(site);
    if (_proxy != null) 
    {
        if (_proxy.Login()) 
        {
            //Login was successful
            //Add channel event handlers so we can determine if something goes wrong
            foreach (IChannel a in site.OutgoingChannels) 
            {
                a.Opened += Channel_Opened;
                a.Faulted += Channel_Faulted;
                a.Closing += Channel_Closing;
                a.Closed += Channel_Closed;
            }
        }
    }
    

    I hope some of this translates and has value for you with NetNamedPipes.

    Edit: More options for capturing the server restarted issue

    When the server restarts it should cause the client's channel to either close or fault. Capturing those events on the client side would give you the option of using reconnect timer until the service is available again.

    private void Channel_Faulted(object sender, EventArgs e)
    {
        IChannel channel = sender as IChannel;
        if (channel != null) 
        {
            channel.Abort();
            channel.Close();
        }
    
        //Disable the keep alive timer now that the channel is faulted
        _keepAliveTimer.Stop();
    
        //The proxy channel should no longer be used
        AbortProxy();
    
        //Enable the try again timer and attempt to reconnect
        _reconnectTimer.Start();
    }
    
    private void _reconnectTimer_Tick(object sender, System.EventArgs e)
    {
        if (_proxy == null) 
        {
            InstanceContext site = new InstanceContext(this);
            _proxy = new StateManagerClient(site);
        }
        if (_proxy != null) 
        {
            if (_proxy.Login()) 
            {
                //The connection is back up
                _reconnectTimer.Stop();
                _keepAliveTimer.Start();
            }
            else 
            {
                //The channel has likely faulted and the proxy should be destroyed
                AbortProxy();
            }
        }
    }
    
    public void AbortProxy()
    {
        if (_proxy != null) 
        {
            _proxy.Abort();
            _proxy.Close();
            _proxy = null;
        }
    }
    

    You would want to ensure the reconnect timer's login attempts are done on a background thread asynchronously so they don't hang the UI every time they attempt to login. YMMV

提交回复
热议问题