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á:
Es necesario recuperar el
ServicePoint
objeto asociado con el nombre del servidor Web actual.Una vez que haya recuperado el
ServicePoint
objeto, llame a laCloseConnectionGroup
función del objeto recuperadoServicePoint
y pase los nombres deConnectionGroupName
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
}
}