简体   繁体   中英

C# Wcf connections causing TCP/IP Port Exhaustion

I'm working on an ASP.NET MVC project and found several connections to a WCF service that are not closed and I think this is causing a TCP/IP Port Exhaustion.

I checked the server at the Resource Monitor/Network/TCP Connections and there are thousands of gray connections as "IPV6 Loopback" and at some point there are so many connections that the server stops responding on the service port.

Existis a dependency injection to work with the connections on the controllers and there is a "CloseChannel" method, but it was not called, I made some changes to it and started calling it in the Dipose method on the controllers to close the connections, but I did not get any results. The loopbacks continue to appear.

Two solutions I think to do is:

  • Remove the dependency injection and create the connection normaly on each time with using.

    Beside closing connections make some changes on the server as described in this post

Doubt: Is there any better option than the ones I proposed? If not, which one is the best in your opinion?

Thank you all!

PS.: Code used today to open and close connections:

This is called onthe controller:

IClient wcfClient = WcfChannel.CreateChannel<IClient>(connectionstr, WcfChannel.WcfBinding.NetTcpBinding);

This is the WcfChannel:

public static class WcfChannel
{
    public static T CreateChannel<T>(string endpointAddress, WcfBinding wcfBinding)
    {
        Binding binding = null;

        #region ReaderQuotas
        XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas()
        {
            MaxDepth = int.MaxValue,
            MaxStringContentLength = int.MaxValue,
            MaxArrayLength = int.MaxValue,
            MaxBytesPerRead = int.MaxValue,
            MaxNameTableCharCount = int.MaxValue
        };
        #endregion

        switch (wcfBinding)
        {
            case WcfBinding.BasicHttpBinding:
            case WcfBinding.NetMsmqBinding:
            case WcfBinding.NetNamedPipeBinding:
                throw new NotImplementedException();

            case WcfBinding.NetTcpBinding:
                binding = new NetTcpBinding()
                {
                    Name = "NetTcpBinding",
                    MaxBufferPoolSize = long.MaxValue,
                    MaxBufferSize = int.MaxValue,
                    MaxReceivedMessageSize = int.MaxValue,
                    ReaderQuotas = readerQuotas,
                    Security = new NetTcpSecurity() { Mode = SecurityMode.None },
                    CloseTimeout = new TimeSpan(0, 5, 0),
                    OpenTimeout = new TimeSpan(0, 5, 0),
                    ReceiveTimeout = new TimeSpan(0, 5, 0),
                    SendTimeout = new TimeSpan(0, 5, 0)
                };
                break;

            case WcfBinding.NetTcpBindingStreamed:
                binding = new NetTcpBinding()
                {
                    Name = "NetTcpBindingStreamed",
                    TransferMode = TransferMode.Streamed,
                    MaxBufferPoolSize = long.MaxValue,
                    MaxBufferSize = int.MaxValue,
                    MaxReceivedMessageSize = int.MaxValue,
                    ReaderQuotas = readerQuotas,
                    Security = new NetTcpSecurity() { Mode = SecurityMode.None },
                    CloseTimeout = new TimeSpan(0, 5, 0),
                    OpenTimeout = new TimeSpan(0, 5, 0),
                    ReceiveTimeout = new TimeSpan(0, 5, 0),
                    SendTimeout = new TimeSpan(0, 5, 0)
                };
                break;
            case WcfBinding.WS2007HttpBinding:
            case WcfBinding.WSHttpBinding:
                throw new NotImplementedException();
            default:
                throw new NotImplementedException();
        }

        EndpointAddress endpoint = new EndpointAddress(endpointAddress);

        var channelFactory = new ChannelFactory<T>(binding, endpoint);
        T channelObj = channelFactory.CreateChannel();

        return channelObj;
    }

    public static void CloseChannel(this object obj)
    {
        if (obj != null)
        {
            try
            {
                (obj as IClientChannel).Close();
            }
            catch (CommunicationException)
            {
                if (obj.GetType().GetMethod("Abort") != null)
                {
                    (obj as IClientChannel).Abort();
                }
            }
            catch (TimeoutException)
            {
                if (obj.GetType().GetMethod("Abort") != null)
                {
                    (obj as IClientChannel).Abort();
                }
            }
            catch (Exception)
            {
                //many connections doesn't have and Abort or close
            }


            if (obj.GetType().GetMethod("Dispose") != null)
            {
                (obj as IDisposable).Dispose();
            }

            obj = null;
        }
    }

    public enum WcfBinding
    {
        BasicHttpBinding,
        NetMsmqBinding,
        NetNamedPipeBinding,
        NetTcpBinding,
        NetTcpBindingStreamed,
        WS2007HttpBinding,
        WSHttpBinding
    }
}

I suspect that your problem is generated by the fact that the WCF session is not managed. The Net TCP Binding is a session based binding and the session needs to be managed. In contrast to ASP.NET, where the session is initiated and managed by the server, in WCF the session is initiated and managed by the client. You can manage the session by using the ServiceContract/SessionMode, OperationContract/IsInitiating/IsTerminating annotation attributes. (documentation here: https://docs.microsoft.com/en-us/dotnet/framework/wcf/using-sessions )

On the client side, you need to call the CloseChannel method after ending the session. Also, you need to verify the channel state on all exception and call the abort method (some consideration regarding the use of Net TCP Binding client side here: https://blogs.msdn.microsoft.com/rodneyviana/2016/02/29/considerations-for-nettcpbindingnetnamedpipebinding-you-may-not-be-aware/ ). Also, on server side, as a best practice, one might want to enable service throttling in order to limit the sessions/service instances ( https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-servicethrottlingbehavior-to-control-wcf-service-performance ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM