Pregunta

Tenemos un httphandler bastante complejo para manejar imágenes. Básicamente, transmite cualquier parte de la imagen en cualquier tamaño que se solicite. Algunos clientes usan este controlador sin ningún problema. Pero tenemos una ubicación que nos da problemas, y ahora también da problemas en mi entorno de desarrollo.

Lo que sucede es que el cliente nunca recibe nada en algunas solicitudes. Entonces, las solicitudes 1 y 2 están bien, pero las solicitudes 3 y 4 nunca terminan.

  • Durante la depuración puedo ver que el servidor está listo y ha completado la solicitud.
  • Sin embargo, el cliente todavía está esperando un resultado (la depuración con fiddler2 muestra que no se recibió respuesta)

El código que usamos para transmitir una imagen es

        if (!context.Response.IsClientConnected)
        {
            imageStream.Close();
            imageStream.Dispose();
            return;
        }

        context.Response.BufferOutput = true;
        context.Response.ContentType = "image/" + imageformat;

        context.Response.AppendHeader("Content-Length", imageStream.Length.ToString());

        if (imageStream != null && imageStream.Length > 0 && context.Response.IsClientConnected)
            context.Response.BinaryWrite(imageStream.ToArray());

        if (context.Response.IsClientConnected)
            context.Response.Flush();

        imageStream.Close();
        imageStream.Dispose();

El imageStream es un MemoryStream con el contenido de una imagen.

Después de la llamada a respuesta. Flush () hacemos más limpieza y escribimos resúmenes en el registro de eventos.

También llamamos GC.Collect () después de cada solicitud, porque los objetos que usamos en la memoria se vuelven muy grandes. Sé que no es una buena práctica, pero ¿podría darnos problemas?

Los problemas con las solicitudes no devueltas ocurren tanto en IIS 5 (Win XP) como en IIS 6 (Win 2003), utilizamos .NET framework v2.

¿Fue útil?

Solución

Un cliente limitará la cantidad de solicitudes simultáneas que hará a cualquier servidor. Además, cuando se solicita de un recurso que requiere el estado de sesión (el valor predeterminado), otras solicitudes de recursos que requieren el estado de sesión se bloquearán.

Al usar HttpWebResponse debe desechar ese objeto o la secuencia devuelta por su método GetResponseStream para completar la conexión.

Su código fue muy confuso. Ha activado el almacenamiento en búfer, ha establecido una longitud de contenido y ha utilizado una descarga. Esto da como resultado algunos encabezados HTTP extraños. Normalmente, con el almacenamiento en búfer activado, dejaría la configuración del encabezado Content-Length en ASP.NET para manejar.

Cuando usa flush ASP.NET asume que posteriormente puede enviar más datos. En este caso, usará transferencia fragmentada. Una vez que se completa la respuesta, se envía un conjunto final de encabezados para el fragmento final, cada fragmento como su propio encabezado de longitud y la longitud total del contenido se deriva de ellos. El primer fragmento debería no tener un encabezado Content-Length, sin embargo, su código está agregando ese encabezado.

Si desactiva el almacenamiento en búfer y bombea los bytes en el flujo de salida usted mismo , entonces debe configurar el encabezado Content-Length usted mismo porque efectivamente el almacenamiento en búfer desactivado significa que usted se responsabiliza exactamente de lo que se envía al cliente. El código de Marc es un ejemplo simple de una bomba de este tipo, aunque usaría un búfer más grande, o en un MemoryStream, el método WriteTo sería más eficiente.

Otros consejos

En primer lugar, hay mejores formas de manejar las transmisiones que usar una matriz para todo (es decir, MemoryStream podría ser innecesario aquí).

Imaginaría un bucle:

const int BUFFER_SIZE = 4096; // pick your poison
bute[] buffer = new byte[BUFFER_SIZE];
int bytesRead;

while((bytesRead = inStream.Read(buffer, 0, BUFFER_SIZE)) > 0)
{
    outStream.Write(buffer, 0, bytesRead);
}

También debe hacer esto con el almacenamiento en búfer deshabilitado ( .Response.BufferOutput = false ).

Respecto al problema, sospecho que no ha escrito suficientes datos / cerrado la respuesta ( .Response.Close () ).

La recolección de basura no debería ser el problema. ¿Por qué estás configurando BufferOutput en true? Dado que solo desea escribir los datos directamente, habría pensado que sería más apropiado establecerlos en falso.

Le sugiero que vaya un nivel más bajo en sus diagnósticos: use Wireshark para ver exactamente lo que sucede en el nivel de red Fiddler es excelente para el nivel HTTP, pero a veces necesitas aún más detalles.

También utilizamos WebRequests para recopilar más información. Esos estaban bloqueando las conexiones. Poner usos alrededor de WebResponses hizo el truco.

using (HttpWebResponse test_resp = (HttpWebResponse)test_req.GetResponse())
{
}

No sabía que esos podrían bloquear otra solicitud, etc. ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top