Descarga se corta (connection TCP terminada) por una razón desconocida

En PHP tengo algo que hace básicamente lo siguiente:

set_time_limit(0); foreach ($files_to_send as $file) { $filesize = filesize($file); $blocksize = 1024 * 1024; // 1MB $outputted = 0; // how many bytes already sent $fid = fopen($file, 'r'); while ($outputted < $filesize) { echo fread($fid, $blocksize); $outputted += $blocksize; } } 

Esto funciona muy bien. Es un server muy lento (Intel Atom dualcore CPU), pero ejecutar wget de localhost obtiene unos 20-24MB / s. La descarga externa básicamente llena la velocidad de carga del server o la velocidad de descarga del cliente, lo que sea más lento. Una descarga de 500MB tarda unos 8 minutos en una connection de 10mbps, como se esperaba.

Alguien de América (el server está cerca de Amsterdam, Países Bajos) menciona que para él la descarga se corta después de medio minuto. Su velocidad de descarga es de aproximadamente 100-200KB / s y corta sin ralentizar primero.

Estoy tratando de diagnosticar el problema. He comprobado el uso de la memory de Apache y es muy estable, lo que significa que la salida de PHP ( echo fread(...); ) se bloquea hasta que el búfer de Apache esté lo suficientemente vacío. Si no, PHP mantendría empujando hacia fuera los bytes y la RAM del server (o al less los amortiguadores de la salida de Apache) funcionaría por completo. Pero ese no es el caso.

También he comprobado si hay errores en el error.log de Apache y error.log PHP. Hay un montón de errores en los últimos días en otros scripts, que se espera y confirma que los loggings están en uso. Si Apache o PHP diera cualquier error, estaría allí. No está ahí.

A continuación, he intentado limitar la tasa de la connection en el lado del cliente. Quizás debería boost la latencia para simular con más precisión las condiciones, pero mi primer bash fue limitar la velocidad a la velocidad reportada por el usuario usando wget --limit-rate=100k . Esto hace que la descarga de corte, aunque wget automáticamente rebashs (y que funciona muy bien, puede reanudar el file, pero supongo que los browseres no lo hará).

Mirando en Wireshark, no hay ninguna razón obvia por la que se corta la descarga lenta. Hay un montón de packages de TCP Window Full y TCP Window Update, pero nada que indique que el server podría ir "sí, no importa esta connection lenta, tengo mejores cosas que hacer". El server envía un FIN en algún momento (un FIN, PSH, ACK con datos en él, para ser precisos) que el cliente responde a unos segundos más tarde con su correspondiente FIN, ACK. El retraso de unos pocos segundos probablemente se deba a que la window TCP está llena (ya que wget consume la secuencia sólo lentamente) y wget no haber leído el package FIN del server todavía.

Curiosamente, el problema no se produce a través de https. Sólo ocurre sobre http simple.

Hay algunas incertidumbres y preguntas en este punto:

  • ¿Esta cosa de la window TCP realmente está ocurriendo en el cliente en el lado de América, o hay otro problema?

  • No sé mucho acerca de las windows TCP (tengo una idea vaga de lo que hace y sé que esta cosa llamada escalado de window existe, pero eso es todo), pero la connection parece estar yendo bien: server de envío de datos, la window del cliente se ejecuta completa , cliente que envía acks un pedacito más adelante, server que envía datos otra vez, etc. Y entonces el server va "ok sí ése es, aquí está el último package. FIN."

  • ¿Quién decide enviar el FIN, Apache o Windows (es un server de Windows)? Si Apache, ¿por qué no registra que está terminando prematuramente una connection?

No estoy seguro de cómo continuar con la solución de este problema de TCP, así que antes de pasar un día en la investigación y las testings me gustaría saber que estoy buscando el problema correcto. Pero, ¿cómo averiguar si este es el problema correcto? Realmente no puedo pedirle al cliente que descargue, instale y trabaje con Wireshark. (Ejecutar una captura de packages en el server es muy intensivo en la CPU y tendría que coordinar una descarga durante la captura, por lo que es una opción de último recurso).

¿Alguien tiene experiencia con un problema como este: ya sea PHP + Apache corte de descargas, o la connection TCP se termina de forma extraña sólo en HTTP (no https)?

¿O alguien tiene ideas para solucionarlo?

El server ejecuta Windows 7 (32 bits) con Apache 2.4.17 y PHP 5.4.25. El server tiene una línea 50 / 50mbps y está detrás de NAT pero tiene el reenvío de puertos configurado. El cliente utiliza Windows 8 de 64 bits con Google Chrome. Si lo desea, puedo proporcionar un pcap capturado por el cliente (15 MB) con el problema, dar una URL para que pueda probarlo usted mismo y vincular al repository Github del código PHP.

  • ¿Qué causa los loggings ACK duplicates?
  • Cookies SYN en máquinas internas
  • El tamaño de la window TCP va a 0 / Wget deja de download?
  • Linux - Conexiones salientes desde el time de espera del process después de reiniciar el process
  • ¿Puedo hacer que la session TCP / IP funcione less de 60 segundos?
  • Extrañas latencias de connection tcp de 3 segundos (Linux, HTTP)
  • IPtables rate-limit, ¿Cuáles son las diferencias entre los modules? Límite reciente
  • Karmic Koala (Ubuntu): habilita a los clientes remotos x a través de TCP
  • ¿ColdFusion utiliza puertos TCP?
  • Limite el número de conexiones TCP en el server Linux, para evitar ataques
  • ¿Cómo reajustar una connection del tcp inmediatamente en ambos extremos en una cierta condición usando linux netfilter / iptables?
  • Escalado de windows de Windows TCP Golpear meseta demasiado temprano
  • Conectar a sphinx en un server remoto
  • El linux y los temas del servidor de Windows, como ubuntu, centos, apache, nginx, debian y consejos de red.