Puede quedarse sin puertos disponibles cuando se utiliza la propiedad ConnectionGroupName de la clase System .net. HttpWebRequest de .NET Framework 2,0 o 4,0

Este artículo le ayudará a resolver el problema en el que podría quedarse sin puertos disponibles al utilizar la ConnectionGroupName propiedad de la System.Net.HttpWebRequest clase en Microsoft .net Framework 2,0 o 4,0.

Versión del producto original:   Microsoft .NET Framework 2,0, 4,0
Número de KB original:   2551125

Síntomas

Está usando la System.Net.HttpWebRequest clase en la aplicación basada en .NET Framework 2,0 o 4,0. Al realizar la solicitud HTTP, se establece la ConnectionGroupName propiedad de la clase en un nombre único cada vez que se usa la clase.

Si continúa enviando solicitudes al mismo servidor con un ConnectionGroupName valor único establecido en las solicitudes salientes cada vez y no permite que el System.Net.ServicePoint objeto subyacente asociado con las solicitudes permanezca inactivo durante el tiempo de inactividad permitido, observará que el uso del puerto de la aplicación crece constantemente y nunca se interrumpe.

Esto hace que el System.Net.ServicePoint objeto subyacente asociado con el HttpWebRequest para crear únicos ConnectionGroup (s) y termine creando nuevos System.Net.Connection para cada uno de ellos ConnectionGroup . Estos objetos subyacentes System.Net.Connection están asociados a una referencia de identificador de sockets Winsock única que permanece abierta en el proceso hasta que el System.Net.ServicePoint objeto tiene una oportunidad de permanecer inactivo durante un período de tiempo limitado. El valor predeterminado de esta hora es de 100 segundos y se rige por la ServicePointManager.MaxServicePointIdleTime propiedad.

Si el ServicePoint objeto nunca permanece inactivo y sigue creando nuevos ConnectionGroup (s) y System.Net.Connection , por lo tanto, un objeto subyacente, observará que la aplicación se ejecutará pronto desde el espacio de sockets o los números de puerto disponibles. El efecto inmediato de este problema es que la aplicación ya no podrá crear nuevos Connection objetos ni iniciar una excepción que indique que no se pudo realizar una operación en un socket porque el sistema carecía de espacio en búfer suficiente o porque había una cola llena que corresponde con el error de Winsock 10055 = WSAENOBUFS.

Si captura un archivo de volcado de bloqueo de su proceso durante este síntoma, verá muchos System.Net.Sockets.Socket objetos, System.Net.ConnectionGroup objetos y objetos System.Net.Connection en el archivo de volcado que no ha sido limpiado por el recolector de elementos no utilizados.

Por ejemplo:

0:000> !dumpheap -type System.Net.Sockets.Socket -stat
total Sock_Count objects
Statistics:
    MT     Count     TotalSize Class Name
<<MT>>     Sock_Count <<Size>> System.Net.Sockets.Socket
Total Sock_Count objects
0:000> !dumpheap -type System.Net.ConnectionGroup -stat
total Group_Count objects
Statistics:
    MT     Count TotalSize Class Name
<<MT>>     Group_Count <<Size>> System.Net.ConnectionGroup
Total Group_Count objects
0:000> !dumpheap -type System.Net.Connection -stat
total Conn_Count objects
Statistics:
    MT     Count TotalSize Class Name
<<MT>>     Conn_Count <<Size>> System.Net.Connection
Total Conn_Count objects

Donde Sock_Count, Group_Count y Conn_Count es el número de objetos Socket , ConnectionGroup objetos y Connection objetos respectivamente y, normalmente, un número grande en miles.

Causa

El uso constante del mismo ServicePoint objeto para crear únicos ConnectionGroup (s) solo permite que el ServicePoint permanezca inactivo, lo que hace que el ServicePoint nunca obtenga una oportunidad de limpiar los objetos subyacentes System.Net.Connection que han estado inactivos durante más tiempo del asignado (valor predeterminado 100 segundos).

Cada uno Connection o Socket reserva un número de puerto local y, cuando se alcanza el límite del sistema (predeterminado 5000), no se pueden realizar conexiones adicionales.

Solución

Si se encuentra en este tipo de problema en el que se muestran muchos System.Net.Connection objetos debido a una creación constante de una ConnectionGroupName propiedad única de la HttpWebRequest clase, se recomienda limitar el número de ConnectionGroup (s) a un número limitado para evitar quedarse sin puertos disponibles. Al limitar el número de ConnectionGroup (s) se asegurará de que el número máximo de Connections que se está abriendo se restringe y no aumenta más allá de los límites disponibles.

Otra alternativa para evitar que se ejecute en este escenario es deshabilitar el comportamiento de mantenimiento de conexiones HTTP de la HttpWebRequest clase estableciendo la KeepAlive propiedad en false. Deshabilitar el comportamiento de mantenimiento de conexiones HTTP activas garantizará que la conexión subyacente se cierre una vez se haya revisado una solicitud, lo que garantiza que la referencia del socket se libere inmediatamente. Esto, a su vez, limpiará el System.Net.Connection y la System.Net.Sockets.Socket referencia y no dependerá de ServicePoint para que su temporizador inactivo expire.

También puede llamar a la System.Net.ServicePoint.CloseConnectionGroup función periódicamente desde la aplicación que liberará las antiguas Connection o las Socket referencias inmediatamente. Para usar esta función sin embargo, deberá:

  1. Es necesario recuperar el ServicePoint objeto asociado con el nombre del servidor Web actual.

  2. Una vez que haya recuperado el ServicePoint objeto, llame a la CloseConnectionGroup función del objeto recuperado ServicePoint y pase los nombres de ConnectionGroupName lo que haya creado hasta ahora en la aplicación y que deba limpiarse.

Puede usar el siguiente código como ejemplo:

void CloseIdleConnectionGroups(String[] strGroups, String strURL)
{
    try
    {
        System.Net.ServicePoint oSP = System.Net.ServicePointManager.FindServicePoint(new Uri(strURL));

        foreach (String strGroup in strGroups)
        {
            oSP.CloseConnectionGroup(strGroup);
        }
    }
    catch (Exception oEx)
    {
        // handle the exception
    }
}

Referencias