La plupart du trafic sur Internet serait contrôlé par ** TCP (Transmission Control Protocol) **. L'une des caractéristiques de TCP est que chaque nœud de transmission ajuste la quantité de données transmises en une seule fois en fonction de ** l'algorithme de contrôle de congestion **. Dans cet article, ns-3 simule le fonctionnement de chaque algorithme, et NumPy + [matplotlib] Visualisez avec (http://matplotlib.org/).
Pour comparer les algorithmes de contrôle de congestion TCP, ns-3 a [tcp-variants-comparaison.cc
](https://www.nsnam.org/docs/release/3.26/doxygen/tcp-variants- Un exemple de scénario appelé comparaison_8cc.html) est préparé. Cependant, si ce script de scénario est utilisé tel quel, il existe un problème en raison du fait que certaines variables d'intérêt dans cet article ne peuvent pas être surveillées (dans ns-3, elles sont appelées ** trace **). Par conséquent, dans cet article, nous allons présenter comment ajouter des informations de trace arbitraires au script de scénario.
Le code source de cet article est entièrement disponible sur Github.
[^ Congestion]: Un mot pour l'image de la congestion dans un réseau.
2.1 ns-3 (Network Simulator 3) ns-3 est un simulateur de réseau d'événements discrets open source. Il est développé pour une utilisation à des fins de recherche et d'enseignement. Cet article suppose l'environnement et la structure de répertoires créés dans l'article suivant.
Simulation de réseau à partir de ns-3.26
2.2 python Dans cet article, NumPy est utilisé pour le traitement des données, et matplotlib est utilisé pour le dessin graphique. Nous avons confirmé l'opération dans l'environnement suivant.
La figure ci-dessous est une image du contrôle de congestion TCP supposé dans cet article. Le nœud émetteur TCP (TCP Sender) dispose de la quantité de données en fonction de l'accusé de réception (accusé de réception, ACK) [^ retardé ACK] [^ numéro ACK] du nœud récepteur (récepteur TCP) et du temps d'aller-retour du signal (Round Trip Time, RTT). Ajustez (DATA).
[^ ACK retardé]: Par souci de simplicité, cet article ne considère pas ACK retardé (accusé de réception différé). Delayed ACK est une méthode pour améliorer l'efficacité d'utilisation du réseau en transmettant plusieurs ACK à la fois.
[^ ACKnumber]: Le numéro d'accusé de réception est strictement le numéro de séquence reçu + la taille du segment. Dans cet article, afin de rendre l'explication intuitive, nous utilisons un diagramme d'image qui ACK le numéro de segment de DATA tel quel.
A proprement parler, l'ajustement de la quantité de données peut être exprimé par la formule $ swnd = min (awnd, cwnd) $. Ici, $ swnd $ est la limite supérieure du nombre de DONNÉES que TCP Sender peut envoyer sans ACK, $ cwnd $ est la taille de la fenêtre (fenêtre d'encombrement) que TCP Sender ajuste de manière autonome, et $ et $ sont TCP. Il s'agit de la taille de la fenêtre (fenêtre publiée) annoncée par le récepteur. L'unité de la formule ci-dessus est appelée un segment et la taille d'un segment est déterminée par la négociation entre l'expéditeur TCP et le récepteur. Puisque $ awnd $ est souvent défini sur une très grande valeur, par souci de simplicité, cet article se concentrera uniquement sur $ cwnd $. Plus $ cwnd $ est grand, plus vous pouvez envoyer de données à la fois. TCP Sender prédit l'occupation du réseau avec le récepteur depuis ACK et RTT, et ajuste de manière autonome la taille de $ cwnd $. La stratégie d'ajustement pour $ cwnd $ est appelée ** contrôle de la congestion ** dans cet article. Le contrôle de la congestion est déterminé par deux facteurs: ** état de congestion [^ diagramme de transition d'état] ** (état de congestion) et ** algorithme ** (algorithme de contrôle de congestion). L'état d'encombrement indique l'état d'encombrement du réseau tel que * OPEN *, * DISORDER *, * RECOVER *, * LOSS *. L'algorithme décrit comment mettre à jour $ cwnd $ dans chaque état de congestion.
[^ Diagramme de transition d'état]: Il est différent du soi-disant diagramme de transition d'état TCP (machine à états finis). Le diagramme de transition d'état couvre le processus de l'établissement de la connexion à la déconnexion, tandis que l'état d'encombrement cible l'état d'encombrement pendant l'établissement de la connexion (ESTABLISHED).
Dans cet article, l'implémentation de ns-3 (~ / ns-3.26 / source / ns-3.26 / src / internet / model / tcp-socket-base.cc
Basé sur docs / release / 3.26 / doxygen / tcp-socket-base_8cc.html)), les quatre types d'encombrement suivants sont supposés.
Dans cet article, les algorithmes de contrôle de congestion suivants sont supposés basés sur [l'implémentation] de ns-3 (https://www.nsnam.org/docs/models/html/tcp.html). TypeId
est comme le nom de l'algorithme dans ns-3. Le code source est stocké dans ~ / ns-3.26 / source / ns-3.26 / src / internet / model
respectivement.
algorithme | TypeId |
Code source |
---|---|---|
NewReno | TcpNewReno |
tcp-congestion-ops.cc |
HighSpeed | TcpHighSpeed |
tcp-highspeed.cc |
Hybla | TcpHybla |
tcp-hybla.cc |
Westwood | TcpWestwood |
tcp-westwood.cc |
Westwood+ | TcpWestwoodPlus |
tcp-westwood.cc |
Vegas | TcpVegas |
tcp-vegas.cc |
Scalable | TcpScalable |
tcp-scalable.cc |
Veno | TcpVeno |
tcp-veno.cc |
Bic | TcpBic |
tcp-bic.cc |
YeAH | TcpYeah |
tcp-yeah.cc |
Illinois | TcpIllinois |
tcp-illinois.cc |
H-TCP | TcpHtcp |
tcp-htcp.cc |
Par exemple, l'un des algorithmes de contrôle de congestion les plus importants, New Reno (Reno), met à jour $ cwnd $ dans chaque état de congestion comme suit: Je vais.
Opportunité de renouvellement | Formule de renouvellement |
---|---|
OPENLorsque ACK est reçu dans l'état (SS) | $ cwnd \gets cwnd + 1$ |
OPENLorsque ACK est reçu dans l'état (CA) | $ \displaystyle cwnd \gets cwnd + \frac{1}{cwnd}$ |
RECOVERYLors de la transition vers l'état | |
RECOVERYLorsqu'un ACK en double est reçu dans l'état | $ \displaystyle cwnd \gets cwnd + 1$ |
RECOVERYDans l'état, recevez un nouvel ACK etOPENLors de la transition vers l'état | $ cwnd \gets ssth$ |
LOSSLors de la transition vers l'état | $ cwnd \gets smss$, |
Ici, $ \ mathit {inflight} $ représente le montant total de DATA pour lequel ACK n'a pas été retourné, et $ smss $ représente la taille minimale du segment. De plus, pour plus de simplicité, les ACK partiels et complets ne sont pas pris en compte. Pour plus de détails sur le fonctionnement de NewReno, reportez-vous à la RFC6582.
NewReno envoie efficacement les DONNÉES en augmentant $ cwnd $ à grande vitesse dans la phase de démarrage lent où la possibilité de congestion est faible, tandis que la phase d'évitement de congestion où la possibilité de congestion est élevée. En, nous avons adopté une stratégie pour éviter les embouteillages soudains en augmentant progressivement $ cwnd $.
Veuillez noter que la formule de mise à jour déclenchée par la réception d'ACK est ** la formule de mise à jour d'ACK pour un segment ** (j'en étais accro ici). Par exemple, lorsque $ cwnd = 4 $, l'expéditeur TCP reçoit ACK [^ delayACK] pour DATA pour 4 segments, donc la mise à jour ci-dessus est effectuée ** 4 fois **.
Il existe trois types d'implémentation TCP dans ns-3, mais dans cet article, ns-3 native ( Seuls les algorithmes implémentés dans src / internet / model
) sont ciblés. En d'autres termes, le majeur [CUBIC] sur Linux (http://dl.acm.org/citation.cfm?id=1400105) et le majeur [CTCP] sur Windows (http://www.dcs.gla.ac.). uk / ~ lewis / CTCP.pdf) est hors de portée. Je voudrais les présenter séparément.
src / internet /
)[^ ack]: ACK retardé.
Dans ce chapitre, nous expliquerons l'exemple de scénario tcp-variantes-comparaison.cc
basé sur celui-ci, ses problèmes et la version modifiée de my-tcp-variants-comparaison.cc
.
ns-3 est [tcp-variants-comparaison.cc
](https://www.nsnam.org/docs/release/3.26/doxygen/tcp-variants-comparison_8cc] pour la comparaison des algorithmes de contrôle de congestion TCP. .html)
Nous avons préparé un exemple de scénario appelé (situé dans ~ / ns-3.26 / source / ns-3.26 / examples / tcp /
). Ce script de scénario peut suivre le changement d'heure des variables suivantes et l'afficher dans un fichier.
Dans ce qui suit, nous expliquerons le code source, en nous concentrant sur ** Trace **, qui est le thème de cet article.
Les lignes 58 à 70 définissent les variables utilisées pour le traçage. bool first *
indique s'il faut ou non afficher la valeur initiale de la cible de trace, et Ptr <OutputStreamWrapper> * Stream
indique le flux pour sortir la cible de trace dans un fichier, respectivement. ʻUint32_t * Value` Représente les variables qui sont temporairement utilisées lors du traitement des valeurs initiales à tracer.
tcp-variants-comparison.cc (lignes 58 à 70)
bool firstCwnd = true;
bool firstSshThr = true;
bool firstRtt = true;
bool firstRto = true;
Ptr<OutputStreamWrapper> cWndStream;
Ptr<OutputStreamWrapper> ssThreshStream;
Ptr<OutputStreamWrapper> rttStream;
Ptr<OutputStreamWrapper> rtoStream;
Ptr<OutputStreamWrapper> nextTxStream;
Ptr<OutputStreamWrapper> nextRxStream;
Ptr<OutputStreamWrapper> inFlightStream;
uint32_t cWndValue;
uint32_t ssThreshValue;
Les lignes 73 à 145 définissent la fonction de rappel de trace «* Tracer ()» et les lignes 147 à 202 définissent la fonction «Trace * ()» qui associe la fonction de rappel à la cible de trace. Je le ferai. Ici, nous allons expliquer l'utilisation de BytesInFlight
, qui est l'une des cibles de trace, à titre d'exemple.
tcp-variants-comparison.cc (lignes 73 à 202)
static void
InFlightTracer (uint32_t old, uint32_t inFlight)
{
*inFlightStream->GetStream () << Simulator::Now ().GetSeconds () << " " << inFlight << std::endl;
}
//=====Abréviation=====
static void
TraceInFlight (std::string &in_flight_file_name)
{
AsciiTraceHelper ascii;
inFlightStream = ascii.CreateFileStream (in_flight_file_name.c_str ());
Config::ConnectWithoutContext ("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/BytesInFlight", MakeCallback (&InFlightTracer));
}
Dans ns-3, toutes les variables ʻAddTraceSource () dans le fichier source (
ns-3.26 / source / ns-3.26 / src / * / model / ) sont définies comme cibles de trace dans le script de scénario. pouvez. Par exemple,
BytesInFlight ci-dessus est [
~ / ns-3.26 / source / ns-3.26 / src / internet / model / tcp-socket-base.cc](https://www.nsnam.org/docs) /release/3.26/doxygen/tcp-socket-base_8cc.html) ʻAddTraceSource ()
. Chaque fois que la variable tracée est mise à jour, ns-3 appelle la fonction de rappel associée à cette variable. Par conséquent, pour définir la cible de trace, il est nécessaire de ** définir la fonction de rappel ** et de ** lier la cible de trace et la fonction de rappel **.
En tant que fonction de rappel, une fonction telle que ʻInFlightTracer () ci-dessus est souvent utilisée. ʻInFlightTracer ()
est une fonction qui affiche l'heure actuelle (Simulator :: Now (). GetSeconds ()
) et la valeur mise à jour (ʻinFlight) à chaque fois. Lorsque vous associez la cible de trace à la fonction de rappel, vous pouvez utiliser la syntaxe
Config :: ConnectWithoutContext (variable, MakeCallback (& func))comme décrit dans
TraceInFlight ()ci-dessus. Ici,
variabledoit décrire le chemin de l'objet à tracer.
/ NodeList / 1 / $ ns3 :: TcpL4Protocol / SocketList / 0 / BytesInFlight signifie la variable
BytesInFlight du socket
SocketList 0, qui se bloque depuis le nœud
NodeList`1.
Pour plus de détails sur la méthode de traçage pour ns-3, reportez-vous à la section 1.10 du Manuel officiel.
Définissez la configuration du réseau avec main ()
à partir de la 204ème ligne. Les détails sont donnés dans le Manuel officiel, et seuls les points sont décrits ici.
La figure ci-dessus est une image de ce scénario. Imaginez une configuration simple avec un expéditeur TCP et un récepteur. Utilisez BulkSendHelper
pour simuler une grande quantité de transmission de données de type FTP. La taille du paquet IP est de 400 octets. Le temps de simulation est de 100 secondes par défaut.
Définissez les arguments de ligne de commande sur les lignes 224 à 243. Comme indiqué dans l'article précédent (http://qiita.com/haltaro/items/b474d924f63692c155c8), vous pouvez définir des arguments de ligne de commande en faisant CommandLine.AddValue ()
.
tcp-variants-comparison.cc (lignes 224 à 243)
CommandLine cmd;
cmd.AddValue ("transport_prot", "Transport protocol to use: TcpNewReno, "
"TcpHybla, TcpHighSpeed, TcpHtcp, TcpVegas, TcpScalable, TcpVeno, "
"TcpBic, TcpYeah, TcpIllinois, TcpWestwood, TcpWestwoodPlus ", transport_prot);
cmd.AddValue ("error_p", "Packet error rate", error_p);
cmd.AddValue ("bandwidth", "Bottleneck bandwidth", bandwidth);
cmd.AddValue ("delay", "Bottleneck delay", delay);
cmd.AddValue ("access_bandwidth", "Access link bandwidth", access_bandwidth);
cmd.AddValue ("access_delay", "Access link delay", access_delay);
cmd.AddValue ("tracing", "Flag to enable/disable tracing", tracing);
cmd.AddValue ("prefix_name", "Prefix of output trace file", prefix_file_name);
cmd.AddValue ("data", "Number of Megabytes of data to transmit", data_mbytes);
cmd.AddValue ("mtu", "Size of IP packets to send in bytes", mtu_bytes);
cmd.AddValue ("num_flows", "Number of flows", num_flows);
cmd.AddValue ("duration", "Time to allow flows to run in seconds", duration);
cmd.AddValue ("run", "Run index (for setting repeatable seeds)", run);
cmd.AddValue ("flow_monitor", "Enable flow monitor", flow_monitor);
cmd.AddValue ("pcap_tracing", "Enable or disable PCAP tracing", pcap);
cmd.AddValue ("queue_disc_type", "Queue disc type for gateway (e.g. ns3::CoDelQueueDisc)", queue_disc_type);
cmd.Parse (argc, argv);
Dans cet article, nous utiliserons en particulier les arguments de ligne de commande suivants.
transport_prot
: l'algorithme de contrôle de congestion peut être spécifié. Dans cet article, nous utiliserons un script shell pour spécifier les 12 types dans l'ordre.tracing
: Vous pouvez spécifier la présence ou l'absence de traçage. Puisqu'il est "False" par défaut, spécifiez "True".duration
: Vous pouvez spécifier le temps de simulation. La valeur par défaut de 100 secondes est trop longue, nous la définirons donc sur 20 secondes dans cet article.prefix_name
: Vous pouvez spécifier le préfixe du nom du fichier de sortie. Avec les paramètres par défaut, un grand nombre de fichiers sera craché directement sous ~ / ns-3.26 / source / ns-3.26 /
, donc modifiez-le pour qu'il crache sous le répertoire data
.De la 460ème ligne à la 476ème ligne, la fonction de paramétrage de la trace (fonction de rappel et la fonction qui associe la cible de trace) telle que celle ci-dessus TraceInFlight ()
est planifiée.
tcp-variants-comparison.cc (lignes 460 à 476)
if (tracing)
{
std::ofstream ascii;
Ptr<OutputStreamWrapper> ascii_wrap;
ascii.open ((prefix_file_name + "-ascii").c_str ());
ascii_wrap = new OutputStreamWrapper ((prefix_file_name + "-ascii").c_str (),
std::ios::out);
stack.EnableAsciiIpv4All (ascii_wrap);
Simulator::Schedule (Seconds (0.00001), &TraceCwnd,
prefix_file_name + "-cwnd.data");
Simulator::Schedule (Seconds (0.00001), &TraceSsThresh,
prefix_file_name + "-ssth.data");
Simulator::Schedule (Seconds (0.00001), &TraceRtt,
prefix_file_name + "-rtt.data");
Simulator::Schedule (Seconds (0.00001), &TraceRto,
prefix_file_name + "-rto.data");
Simulator::Schedule (Seconds (0.00001), &TraceNextTx,
prefix_file_name + "-next-tx.data");
Simulator::Schedule (Seconds (0.00001), &TraceInFlight,
prefix_file_name + "-inflight.data");
Simulator::Schedule (Seconds (0.1), &TraceNextRx,
prefix_file_name + "-next-rx.data");
}
Dans ns-3, vous pouvez programmer l'exécution de func (args, ...)
à time
avec la syntaxeSimulator :: Schedule (time, & func, args, ...)
.
Cependant, je ne sais pas pourquoi vous ne devriez pas Trace * ()
dans le texte local. Je pense qu'il y a probablement un problème avec le timing de la création des objets ...
tcp-variants-comparaison.cc
tcp-variants-comparaison.cc
est un script de scénario très bien conçu avec lequel vous pouvez jouer simplement en modifiant les arguments de la ligne de commande. Mais je ne peux pas retracer les ACK ou les conditions de congestion qui nous intéressent!
Heureusement, la variable LowestRxAck
pour le dernier ACK et la variable CongState
pour l'état de congestion sont tcp-socket-base.cc
release / 3.26 / doxygen / tcp-socket-base_8cc.html) ʻAddTraceSource () `. Par conséquent, vous pouvez les ajouter à la cible de trace avec seulement quelques modifications du script de scénario. Dans ce qui suit, nous présenterons la méthode.
my-tcp-variants-comparaison.cc
Tout d'abord, copiez l'original tcp-variantes-comparaison.cc
dans ~ / ns-3.26 / source / ns-3.26 / scratch
et renommez-le en my-tcp-variantes-comparaison.cc
Faire.
$ cd ~/ns-3.26/source/ns-3.26
$ cp examples/tcp/tcp-variants-comparison.cc scratch/my-tcp-variants-comparison.cc
Afin d'ajouter ACK et l'état de congestion à la cible de trace, ajoutez des variables de trace, définissez la fonction de rappel de trace et planifiez les paramètres de trace.
Ajoutez le flux ʻackStreampour le traçage ACK et le flux
congStateStream` pour le traçage de l'état de congestion.
cpp:my-tcp-variants-comparison.cc(tcp-variants-comparison.Equivalent aux lignes 58 à 70 de cc)
bool firstCwnd = true;
bool firstSshThr = true;
bool firstRtt = true;
bool firstRto = true;
Ptr<OutputStreamWrapper> cWndStream;
Ptr<OutputStreamWrapper> ssThreshStream;
Ptr<OutputStreamWrapper> rttStream;
Ptr<OutputStreamWrapper> rtoStream;
Ptr<OutputStreamWrapper> nextTxStream;
Ptr<OutputStreamWrapper> nextRxStream;
Ptr<OutputStreamWrapper> inFlightStream;
Ptr<OutputStreamWrapper> ackStream; // NEW!
Ptr<OutputStreamWrapper> congStateStream; // NEW!
uint32_t cWndValue;
uint32_t ssThreshValue;
Ajoutez la fonction de rappel ʻAckTrace () pour le traçage ACK et la fonction de rappel
CongStateTracer () pour le traçage de l'état de congestion, respectivement. L'état de congestion est le type d'énumération
TcpSocketState :: TcpCongState_t défini dans
tcp-socket-base.h. Ajoutez également les fonctions
TraceAck ()et
TraceCongState ()` qui associent respectivement la fonction de rappel ci-dessus à la variable à tracer.
cpp:my-tcp-variants-comparison.cc(tcp-variants-comparison.Equivalent aux lignes 73 à 202 de cc)
static void
AckTracer (SequenceNumber32 old, SequenceNumber32 newAck)
{
*ackStream->GetStream () << Simulator::Now ().GetSeconds () << " " << newAck << std::endl;
}
static void
CongStateTracer (TcpSocketState::TcpCongState_t old, TcpSocketState::TcpCongState_t newState)
{
*congStateStream->GetStream () << Simulator::Now ().GetSeconds () << " " << newState << std::endl;
}
//=====Abréviation=====
static void
TraceAck (std::string &ack_file_name)
{
AsciiTraceHelper ascii;
ackStream = ascii.CreateFileStream (ack_file_name.c_str ());
Config::ConnectWithoutContext ("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/HighestRxAck", MakeCallback (&AckTracer));
}
static void
TraceCongState (std::string &cong_state_file_name)
{
AsciiTraceHelper ascii;
congStateStream = ascii.CreateFileStream (cong_state_file_name.c_str ());
Config::ConnectWithoutContext ("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/CongState", MakeCallback (&CongStateTracer));
}
Enfin, planifiez les éléments ci-dessus TraceAck ()
et TraceCongState ()
.
cpp:my-tcp-variants-comparison.cc(tcp-variants-comparison.cc Équivaut aux lignes 460 à 476)
if (tracing)
{
// =====Abréviation=====
Simulator::Schedule (Seconds (0.00001), &TraceAck, prefix_file_name + "-ack.data"); // NEW!
Simulator::Schedule (Seconds (0.00001), &TraceCongState, prefix_file_name + "-cong-state.data"); // NEW!
}
my-tcp-variants-comparaison.cc
Vous pouvez compiler my-tcp-variants-comparaison.cc
en faisant. / Waf
dans le répertoire ~ / ns-3.26 / source / ns-3.26
.
$ ./waf
Waf: Entering directory '~/ns-3.26/source/ns-3.26/source/ns-3.26/build'
[ 985/2524] Compiling scratch/my-tcp-variants-comparison.cc
[2501/2524] Linking build/scratch/my-tcp-variants-comparison
Waf: Leaving directory '~/ns-3.26/source/ns-3.26/source/ns-3.26/build'
Build commands will be stored in build/compile_commands.json
'build' finished successfully (3.240s)
Modules built:
antenna aodv applications
bridge brite (no Python) buildings
click config-store core
csma csma-layout dsdv
dsr energy fd-net-device
flow-monitor internet internet-apps
lr-wpan lte mesh
mobility mpi netanim (no Python)
network nix-vector-routing olsr
point-to-point point-to-point-layout propagation
sixlowpan spectrum stats
tap-bridge test (no Python) topology-read
traffic-control uan virtual-net-device
wave wifi wimax
xgpon (no Python)
Modules not built (see ns-3 tutorial for explanation):
openflow visualizer
Commencez par créer le répertoire de stockage de données data
.
$ mkdir ~/ns-3.26/source/ns-3.26/data
Exécutez le script shell suivant pour expérimenter les 12 types d'algorithmes. Comme présenté dans Article précédent, vous pouvez passer la valeur «value» à l'argument de ligne de commande «arg» par «--arg = valeur». Je vais. transport_prot
est l'algorithme de contrôle de la congestion, prefix_name
est le préfixe du nom du fichier de sortie, tracing
est la présence ou l'absence de traçage et duration
est le [s] temps de simulation.
compare-tcp-algorithms.sh
#!/bin/bash
ALGORITHMS=(TcpNewReno TcpHighSpeed TcpHybla TcpWestwood TcpWestwoodPlus \
TcpVegas TcpScalable TcpVeno TcpBic TcpYeah TcpIllinois TcpHtcp)
for algo in ${ALGORITHMS[@]}; do
echo "----- Simulating $algo -----"
./waf --run "my-tcp-variants-comparison --transport_prot=$algo --prefix_name='data/$algo' --tracing=True --duration=20"
done
Pour l'instant, traçons $ cwnd $ et $ ssth $ de tous les algorithmes et le changement d'état de congestion avec le plot_cwnd_all_algorithms ()
suivant.
plottcpalgo.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
#Il s'agit d'une fonction de mise en forme des données.
def get_data(algo, variable='cwnd', duration=20.):
file_name = 'data/Tcp' + algo + '-' + variable + '.data'
data = np.empty((0, 2)) #Initialisation
#Récupérez les données du fichier.
for line in open(file_name, 'r'):
data = np.append(
data, np.array([map(float, line[:-1].split())]),
axis=0)
data = data.T
#Extraire uniquement les données inférieures à la durée, à la fin[duration, data[1,-1]]À
#ajouter. C'est un processus pour tracer magnifiquement jusqu'à la durée.
data = data[:, data[0] < duration]
if len(data[0])==0:
data = np.append(
data, np.array([[duration, 0]]).T,
axis=1)
else:
data = np.append(
data, np.array([[duration, data[1, -1]]]).T,
axis=1)
return data
def plot_cwnd_all_algorithms(duration=20.):
algos = ['NewReno', 'HighSpeed', 'Hybla', 'Westwood', 'WestwoodPlus',
'Vegas', 'Scalable', 'Veno', 'Bic', 'Yeah', 'Illinois', 'Htcp']
segment = 340 #Dans cette configuration expérimentale, la longueur du segment est de 340 octets.
plt.figure(figsize=(15, 10))
for i, algo in enumerate(algos):
plt.subplot(3, 4, i + 1)
#Acquisition des données cwnd, ssth, état de congestion
cwnd_data = get_data(algo, 'cwnd', duration)
ssth_data = get_data(algo, 'ssth', duration)
state_data = get_data(algo, 'cong-state', duration)
#Les couleurs sont différentes selon l'état de congestion.
#OPEN (bleu), DISORDER (vert), RECOVERY (jaune), LOSS (rouge)
plt.fill_between(cwnd_data[0], cwnd_data[1] / segment,
facecolor='lightblue') #L'état initial est OPEN (bleu)
for n in range(len(state_data[0])-1):
fill_range = cwnd_data[0] >= state_data[0, n]
if state_data[1, n]==1: # 1: DISORDER
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='lightgreen')
elif state_data[1, n]==3: # 3: RECOVERY
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='khaki')
elif state_data[1, n]==4: # 4: LOSS
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='lightcoral')
else: # OPEN
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='lightblue')
#Tracés de cwnd (ligne continue) et ssth (ligne pointillée).
plt.plot(cwnd_data[0], cwnd_data[1] / segment, drawstyle='steps-post')
plt.plot(ssth_data[0], ssth_data[1] / segment, drawstyle='steps-post',
color='b', linestyle='dotted')
plt.ylim(0, 1200) #La valeur initiale de ssth étant énorme, définissez la limite supérieure avec ylim
plt.title(algo)
#Enregistrer et afficher des diagrammes
plt.savefig('data/TcpAll' + str(duration).zfill(3) + '-cwnd.png')
plt.show()
L'axe horizontal correspond au temps [s] et l'axe vertical correspond à $ cwnd $ et $ ssth $ [segment]. $ cwnd $ est une ligne continue et $ ssth $ est une ligne pointillée. Les couleurs sont colorées en fonction de l'état de congestion. $ OPEN $ est bleu, $ DISORDER $ est vert, $ RECOVERY $ est jaune et $ LOSS $ est rouge. L'individualité de chaque algorithme est ressortie plus fortement que prévu initialement.
Ensuite, tracez $ cwnd $, ACK et RTT de chaque algorithme avec le plot_cwnd_ack_rtt_each_algorithm ()
suivant.
plot_cwnd_ack_rtt_each_algorithm()
def plot_cwnd_ack_rtt_each_algorithm(duration=20.):
algos = ['NewReno', 'HighSpeed', 'Hybla', 'Westwood', 'WestwoodPlus',
'Vegas', 'Scalable', 'Veno', 'Bic', 'Yeah', 'Illinois', 'Htcp']
segment = 340 #Dans cette configuration expérimentale, la longueur du segment est de 340 octets.
plt.figure()
for algo in algos:
plt.subplot(311) #Tracé de cwnd, ssth et congestion
#Acquisition des données cwnd, ssth, état de congestion
cwnd_data = get_data(algo, 'cwnd', duration)
ssth_data = get_data(algo, 'ssth', duration)
state_data = get_data(algo, 'cong-state', duration)
#Les couleurs sont différentes selon l'état de congestion.
#OPEN (bleu), DISORDER (vert), RECOVERY (jaune), LOSS (rouge)
plt.fill_between(cwnd_data[0], cwnd_data[1] / segment,
facecolor='lightblue') #L'état initial est OPEN (bleu)
for n in range(len(state_data[0])-1):
fill_range = cwnd_data[0] >= state_data[0, n]
if state_data[1, n]==1: # 1: DISORDER
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='lightgreen')
elif state_data[1, n]==3: # 3: RECOVERY
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='khaki')
elif state_data[1, n]==4: # 4: LOSS
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='lightcoral')
else: # OPEN
plt.fill_between(
cwnd_data[0, fill_range], cwnd_data[1, fill_range] / segment,
facecolor='lightblue')
#Tracés de cwnd (ligne continue) et ssth (ligne pointillée).
plt.plot(cwnd_data[0], cwnd_data[1] / segment, drawstyle='steps-post',
color='b', label='cwnd')
plt.plot(ssth_data[0], ssth_data[1] / segment, drawstyle='steps-post',
color='b', linestyle='dotted', label='ssth')
ymax = max(cwnd_data[1] / segment)*1.1
plt.ylim(0, ymax) #La valeur initiale de ssth étant énorme, définissez la limite supérieure avec ylim
plt.ylabel('cwnd [segment]')
plt.legend()
plt.title(algo)
plt.subplot(312) #Graphique ACK
ack_data = get_data(algo, 'ack', duration)
plt.plot(ack_data[0], ack_data[1] / segment, drawstyle='steps-post',
color='r')
plt.ylabel('ACK [segment]')
plt.subplot(313) #Graphique RTT
rtt_data = get_data(algo, 'rtt', duration)
plt.plot(rtt_data[0], rtt_data[1], drawstyle='steps-post', color='g')
plt.ylabel('RTT[s]')
plt.xlabel('Time [s]')
#Enregistrer l'image.
plt.savefig('data/Tcp' + algo + 'Sub-' + str(int(duration)).zfill(3) +
'-cwnd-ack-rtt.png')
plt.clf()
plt.show()
Dans ce qui suit, nous analyserons les résultats en utilisant NewReno comme exemple. De plus, pour votre information, les résultats d'autres algorithmes sont également inclus.
NewReno
Environ 1,93 [s], trois ACK en double sont reçus et l'état passe à l'état $ RECOVERY $. Débit approximatif à ce moment:
\frac{cwnd}{RTT} \simeq
\frac{321\rm{[segment]} \cdot 340 \rm{[byte/segment] \cdot 8 \rm{[bit/byte]}}}{0.33[s]} \simeq 2.3 \rm{[Mbps]}
Ici, la bande passante de la liaison de goulot d'étranglement était de 2,0 Mbps (voir la section 4.1), donc ce n'est pas anormal en cas de congestion [^ analyse]. Après la transition vers $ RECOVERY $, vous pouvez voir que les mises à jour ACK et RTT se sont arrêtées. Vous pouvez également voir que les mises à jour pour $ cwnd $ et $ ssth $ sont cohérentes avec la section 3.3. Autour de 3,26 [s], il expire sans recevoir de nouvel ACK et passe à l'état $ LOSS $. Vous pouvez voir que les mises à jour de $ cwnd $ et $ ssth $ sont cohérentes avec la section 3.3. Aux alentours de 4,69 [s], un nouvel ACK est finalement reçu et l'état passe à l'état $ OPEN $.
[^ Analyse]: Peut-être. Je pense qu'une analyse plus détaillée telle que l'analyse de la file d'attente est nécessaire, mais je suis épuisé ...
Pour votre information, les résultats d'autres algorithmes sont également affichés.
Dans cet article, j'ai utilisé ns-3 pour simuler le contrôle de congestion TCP et je l'ai visualisé avec python. En tant que débutant, j'ai pu avoir une idée de TCP. Nous avons également réaffirmé l'excellence du scénario de l'échantillon ns-3. Désormais, CUBIC et CTCP Je voudrais essayer d'implémenter des algorithmes majeurs tels que) et les derniers algorithmes tels que Remy. Alternativement, je pense qu'il serait bon d'observer la concurrence entre différents algorithmes. Merci d'avoir lu jusqu'au bout!
En créant cet article, j'ai fait référence à ce qui suit. Merci beaucoup!