Question

Supposons que vous ayez un programme qui lit depuis un socket. Comment maintenir le taux de téléchargement en dessous d’un certain seuil?

Était-ce utile?

La solution

Au niveau de la couche application (à l'aide d'une API de type socket Berkeley), il vous suffit de regarder l'horloge et de lire ou d'écrire des données à la vitesse que vous souhaitez limiter.

Si vous ne lisez que 10 kbps en moyenne, mais que la source envoie plus que cela, tous les tampons qui s’y trouvent finissent par se remplir. TCP / IP le permet, et le protocole fera en sorte que l'expéditeur ralentisse (au niveau de la couche application, tout ce que vous devez savoir, c'est qu'à l'autre extrémité, le blocage des appels en écriture bloquera, les écritures non bloquantes échoueront et les processus asynchrones. les écritures ne seront pas terminées tant que vous ne aurez pas lu suffisamment de données pour le permettre).

Au niveau de l'application, vous ne pouvez qu'être approximatif. Vous ne pouvez pas garantir de limites strictes telles que "10 Ko maximum ne dépasseront pas un point donné du réseau en une seconde". Mais si vous gardez une trace de ce que vous avez reçu, vous pourrez obtenir la moyenne juste à long terme.

Autres conseils

En supposant un transport réseau, basé sur TCP / IP, les paquets sont envoyés en réponse aux paquets ACK / NACK en sens inverse.

En limitant le nombre de paquets accusant réception des paquets entrants, vous réduisez également le taux d'envoi de nouveaux paquets.

Cela peut paraître un peu imprécis. Il est donc peut-être optimal de surveiller le débit en aval et d’ajuster le taux de réponse de manière adaptative jusqu’à ce qu’il tombe dans une limite confortable. (Cela se produira très vite cependant, vous envoyez des dizaines d'acks par seconde)

C’est comme quand on limite un jeu à un certain nombre de FPS.

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

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

De cette façon, vous vous assurez que le taux de rafraîchissement du jeu sera au maximum en FPS. De la même manière, DrawScene peut être la fonction utilisée pour pomper des octets dans le flux de socket.

Si vous lisez depuis un socket, vous n’avez aucun contrôle sur la bande passante utilisée - vous lisez le tampon du système d’exploitation de ce socket, et rien de ce que vous dites ne fera en sorte que la personne qui écrit dans le socket écrit moins de données (sauf , bien sûr, vous avez élaboré un protocole pour cela).

Tout ce que la lecture ferait lentement serait de remplir la mémoire tampon et de provoquer un blocage éventuel au niveau du réseau - mais vous ne pouvez contrôler ni comment ni quand cela se produira.

Si vous voulez vraiment lire autant de données à la fois, vous pouvez faire quelque chose comme ça:

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

wget semble le gérer avec l'option --limit-rate. Voici à partir de la page de manuel:

  

Notez que Wget implémente la limitation   en dormant la quantité appropriée de   temps après une lecture du réseau qui a pris   moins de temps que spécifié par le   taux. Finalement, cette stratégie provoque   le transfert TCP pour ralentir à   approximativement le taux spécifié.   Cependant, cela peut prendre du temps pour   cet équilibre à atteindre, alors ne le faites pas   être surpris si limiter le taux   ne fonctionne pas bien avec très petit   fichiers.

Comme d'autres l'ont dit, le noyau du système d'exploitation gère le trafic et vous ne faites que lire une copie des données hors de la mémoire du noyau. Pour limiter approximativement le débit d’une seule application, vous devez retarder la lecture des données et permettre aux paquets entrants d’être tamponnés dans le noyau, ce qui ralentira l’accusé de réception des paquets entrants et réduira le débit de ce socket.

Si vous souhaitez ralentir tout le trafic sur la machine, vous devez ajuster les tailles de vos tampons TCP entrants. Sous Linux, vous affecteriez cette modification en modifiant les valeurs de / proc / sys / net / ipv4 / tcp_rmem (taille de la mémoire tampon en lecture) et d’autres fichiers tcp_ *.

Pour ajouter à la réponse de Branan:

Si vous limitez volontairement la vitesse de lecture du côté du récepteur, les files d’attente finiront par se remplir aux deux extrémités. Ensuite, l'expéditeur bloquera l'appel send () ou retournera l'appel send () avec une longueur envoyée inférieure à la longueur attendue transmise à l'appel send ().

Si l'expéditeur n'est pas prêt à gérer ce problème en suspendant ses activités et en essayant de renvoyer ce qui ne correspond pas aux tampons du système d'exploitation, vous risquez d'avoir des problèmes de connexion (l'expéditeur peut détecter cela comme une erreur) ou de perdre des données expéditeur peut ignorer inconsciemment des données qui ne rentrent pas dans les mémoires tampon du système d'exploitation).

Définissez les tampons d'envoi et de réception de petite prise, par exemple 1k ou 2k, de sorte que la bande passante * délai produit = la taille de la mémoire tampon. Vous ne pourrez peut-être pas le faire assez petit avec des liens rapides.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top