Pregunta

Supongamos que tiene un programa que lee desde un socket.¿Cómo se mantiene la tasa de descarga por debajo de un determinado umbral?

¿Fue útil?

Solución

En la capa de aplicación (usando una API estilo socket Berkeley), simplemente mira el reloj y lee o escribe datos a la velocidad que desea limitar.

Si solo lee 10 kbps en promedio, pero la fuente envía más que eso, eventualmente todos los buffers entre ella y usted se llenarán.TCP/IP permite esto, y el protocolo se encargará de que el remitente disminuya la velocidad (en la capa de aplicación, probablemente todo lo que necesita saber es que en el otro extremo, las llamadas de escritura con bloqueo se bloquearán, las escrituras sin bloqueo fallarán y las llamadas de escritura asincrónicas se bloquearán). las escrituras no se completarán hasta que haya leído suficientes datos para permitirlo).

En la capa de aplicación sólo puede ser aproximado: no puede garantizar límites estrictos como "no más de 10 kb pasarán por un punto determinado de la red en un segundo".Pero si realiza un seguimiento de lo que ha recibido, puede obtener el promedio correcto a largo plazo.

Otros consejos

Suponiendo un transporte de red, basado en TCP/IP, los paquetes se envían en respuesta a los paquetes ACK/NACK que van en sentido contrario.

Al limitar la velocidad de los paquetes que acusan recibo de los paquetes entrantes, a su vez reducirá la velocidad a la que se envían los nuevos paquetes.

Puede ser un poco impreciso, por lo que posiblemente sea óptimo monitorear la tasa descendente y ajustar la tasa de respuesta de manera adaptativa hasta que caiga dentro de un umbral cómodo.(Esto sucederá muy rápido, sin embargo, envías dosis de ataques por segundo)

Es como cuando se limita un juego a una determinada cantidad de FPS.

extern int FPS;
....    
timePerFrameinMS = 1000/FPS;

while(1) {
time = getMilliseconds();
DrawScene();
time = getMilliseconds()-time;
if (time < timePerFrameinMS) {
   sleep(timePerFrameinMS - time);
}
}

De esta manera te aseguras de que la frecuencia de actualización del juego sea como máximo de FPS.De la misma manera, DrawScene puede ser la función utilizada para bombear bytes al flujo del socket.

Si estás leyendo desde un socket, no tienes control sobre el ancho de banda utilizado: estás leyendo el buffer del sistema operativo de ese socket y nada de lo que digas hará que la persona que escribe en el socket escriba menos datos (a menos, por supuesto, , has elaborado un protocolo para eso).

Todo lo que haría esa lectura lenta es llenar el búfer y provocar una eventual parada en el extremo de la red, pero no tienes control de cómo ni cuándo sucede esto.

Si realmente desea leer solo una cantidad limitada de datos a la vez, puede hacer algo como esto:

ReadFixedRate() {
  while(Data_Exists()) {
    t = GetTime();
    ReadBlock();
    while(t + delay > GetTime()) {
      Delay()'
    }
  }
}

wget parece gestionarlo con la opción --limit-rate.Aquí está la página de manual:

Tenga en cuenta que WGET implementa la limitación al dormir la cantidad de tiempo apropiada después de una lectura de una red que tomó menos tiempo que el especificado por la tasa.Finalmente, esta estrategia hace que la transferencia de TCP disminuya la velocidad a aproximadamente la tasa especificada.Sin embargo, puede tomar algún tiempo para lograr este saldo, así que no se sorprenda si limitar la tasa no funciona bien con archivos muy pequeños.

Como han dicho otros, el kernel del sistema operativo administra el tráfico y usted simplemente lee una copia de los datos de la memoria del kernel.Para limitar aproximadamente la velocidad de una sola aplicación, debe retrasar las lecturas de los datos y permitir que los paquetes entrantes se almacenen en el kernel, lo que eventualmente ralentizará el reconocimiento de los paquetes entrantes y reducirá la velocidad en ese socket.

Si desea ralentizar todo el tráfico hacia la máquina, debe ajustar los tamaños de los buffers TCP entrantes.En Linux, este cambio se podría realizar alterando los valores en /proc/sys/net/ipv4/tcp_rmem (tamaños del búfer de memoria de lectura) y otros archivos tcp_*.

Para agregar a la respuesta de Branan:

Si limita voluntariamente la velocidad de lectura en el extremo del receptor, eventualmente las colas se llenarán en ambos extremos.Luego, el remitente bloqueará su llamada send() o regresará de la llamada send() con una longitud de envío menor que la longitud esperada transmitida a la llamada send().

Si el remitente no está listo para lidiar con este caso durmiendo e intentando reenviar lo que no cabe en los buffers del sistema operativo, terminará teniendo problemas de conexión (el remitente puede detectar esto como un error) o perderá datos (el remitente puede, sin saberlo, descartar datos que no caben en los buffers del sistema operativo).

Establezca búferes de envío y recepción de sockets pequeños, digamos 1k o 2k, de modo que el producto ancho de banda*retraso = el tamaño del búfer.Es posible que no puedas hacerlo lo suficientemente pequeño a través de enlaces rápidos.

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