[PYTHON] Beobachten Sie die TCP-Überlastungskontrolle mit ns-3

1. Zuallererst

Der meiste Verkehr im Internet soll von ** TCP (Transmission Control Protocol) ** gesteuert werden. Eines der Merkmale von TCP ist, dass jeder sendende Knoten die gleichzeitig übertragene Datenmenge basierend auf dem ** Überlastungssteuerungsalgorithmus ** anpasst. In diesem Artikel simuliert ns-3 die Funktionsweise jedes Algorithmus und NumPy + [matplotlib] Visualisieren mit (http://matplotlib.org/). Um TCP-Überlastungskontrollalgorithmen zu vergleichen, verfügt ns-3 über [tcp-videos-compare.cc](https://www.nsnam.org/docs/release/3.26/doxygen/tcp-variants- Ein Beispielszenario mit dem Namen "compare_8cc.html" wird vorbereitet. Wenn dieses Szenarioskript jedoch unverändert verwendet wird, besteht das Problem, dass einige in diesem Artikel interessierende Variablen nicht überwacht werden können (in ns-3 werden sie als ** trace ** bezeichnet). In diesem Artikel wird daher erläutert, wie Sie dem Szenarioskript beliebige Ablaufverfolgungsinformationen hinzufügen.

TcpAll20.0-cwnd.png

Der Quellcode für diesen Artikel befindet sich ausschließlich auf Github.

[^ Überlastung]: Ein Wort für das Bild der Überlastung in einem Netzwerk.

2. Umweltbau

2.1 ns-3 (Network Simulator 3) ns-3 ist ein Open-Source-Simulator für diskrete Ereignisnetzwerke. Es wurde für Forschungs- und Bildungszwecke entwickelt. Dieser Artikel setzt die im folgenden Artikel erstellte Umgebung und Verzeichnisstruktur voraus.

Netzwerksimulation beginnend mit ns-3.26

2.2 python In diesem Artikel wird NumPy für die Datenverarbeitung und matplotlib für das Zeichnen von Grafiken verwendet. Wir haben den Betrieb in der folgenden Umgebung bestätigt.

3. Überlastungskontrolle in TCP

3.1 Übersicht

Die folgende Abbildung zeigt die in diesem Artikel angenommene TCP-Überlastungskontrolle. Der TCP-Sendeknoten (TCP-Sender) verfügt über die Datenmenge gemäß der Bestätigung (Bestätigung, ACK) [^ verzögerte ACK] [^ ACK-Nummer] vom empfangenden Knoten (TCP-Empfänger) und der Signalumlaufzeit (Round Trip Time, RTT). Anpassen (DATA).

[^ verzögertes ACK]: Der Einfachheit halber wird in diesem Artikel das verzögerte ACK (verzögerte Bestätigung) nicht berücksichtigt. Delayed ACK ist eine Methode zur Verbesserung der Netzwerknutzungseffizienz durch gleichzeitige Übertragung mehrerer ACKs.

[^ ACKnumber]: Die Bestätigungsnummer ist ausschließlich die empfangene Sequenznummer + Segmentgröße. In diesem Artikel verwenden wir ein Bilddiagramm, das die Segmentnummer von DATA so wie sie ist bestätigt, um die Erklärung intuitiv zu gestalten.

model.png

Genau genommen kann die Anpassung der Datenmenge durch die Formel $ swnd = min (awnd, cwnd) $ ausgedrückt werden. Hier ist $ swnd $ die Obergrenze für die Anzahl der DATEN, die der TCP-Absender ohne ACK senden kann, $ cwnd $ ist die Fenstergröße (Überlastungsfenster), die der TCP-Absender autonom anpasst, und $ und $ ist TCP. Dies ist die vom Empfänger angekündigte Fenstergröße (angekündigtes Fenster). Die Einheit der obigen Formel wird als Segment bezeichnet, und die Größe eines Segments wird durch die Aushandlung zwischen TCP-Sender und -Empfänger bestimmt. Da $ awnd $ der Einfachheit halber häufig auf einen sehr großen Wert eingestellt ist, konzentriert sich dieser Artikel nur auf $ cwnd $. Je größer $ cwnd $, desto mehr Daten können Sie gleichzeitig senden. Der TCP-Sender sagt voraus, wie beschäftigt das Netzwerk mit dem Empfänger von ACK und RTT ist, und passt die Größe von $ cwnd $ autonom an. Die Anpassungsstrategie für $ cwnd $ wird in diesem Artikel als ** Überlastungskontrolle ** bezeichnet. Die Überlastungskontrolle wird durch zwei Faktoren bestimmt: ** Überlastungszustand [^ Zustandsübergangsdiagramm] ** (Überlastungszustand) und ** Algorithmus ** (Überlastungskontrollalgorithmus). Der Überlastungsstatus zeigt den Überlastungsstatus des Netzwerks an, z. B. * OPEN *, * DISORDER *, * RECOVER *, * LOSS *. Der Algorithmus beschreibt, wie $ cwnd $ in jedem Überlastungsstatus aktualisiert wird.

[^ Zustandsübergangsdiagramm]: Es unterscheidet sich vom sogenannten TCP-Zustandsübergangsdiagramm (Finite State Machine). Das Zustandsübergangsdiagramm deckt den Zeitraum vom Verbindungsaufbau bis zur Trennung ab, während der Überlastungszustand auf den Überlastungszustand während des Verbindungsaufbaus abzielt (ESTABLISHED).

3.2 Überlastungszustand

In diesem Artikel wird die Implementierung von ns-3 (~ / ns-3.26 / source / ns-3.26 / src / internet / model / tcp-socket-base.cc beschrieben. Basierend auf docs / release / 3.26 / doxygen / tcp-socket-base_8cc.html)) werden die folgenden vier Arten von Überlastungen angenommen.

state.png

3.3 Überlastungskontrollalgorithmus

In diesem Artikel werden die folgenden Überlastungssteuerungsalgorithmen basierend auf der [Implementierung] von ns-3 (https://www.nsnam.org/docs/models/html/tcp.html) angenommen. TypeId ist wie der Name des Algorithmus in ns-3. Der Quellcode wird jeweils in "~ / ns-3.26 / source / ns-3.26 / src / internet / model" gespeichert.

Algorithmus TypeId Quellcode
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

Beispielsweise aktualisiert einer der wichtigsten Algorithmen zur Überlastungskontrolle, New Reno (Reno), $ cwnd $ in jedem Überlastungsstatus wie folgt: Ich werde.

Erneuerungsmöglichkeit Erneuerungsformel
OPENWenn ACK im Status (SS) empfangen wird $ cwnd \gets cwnd + 1$
OPENWenn ACK im Status (CA) empfangen wird $ \displaystyle cwnd \gets cwnd + \frac{1}{cwnd}$
RECOVERYBeim Übergang in den Staat ssth \gets max(\mathit{inflight} /2, 2 \cdot smss), cwnd \gets ssth +3
RECOVERYWenn eine doppelte ACK im Status empfangen wird $ \displaystyle cwnd \gets cwnd + 1$
RECOVERYIn dem Zustand erhalten Sie eine neue ACK undOPENBeim Übergang in den Staat $ cwnd \gets ssth$
LOSSBeim Übergang in den Staat $ cwnd \gets smss$, ssth \gets max(\mathit{inflight} /2, 2 \cdot smss)

Hier steht $ \ mathit {inflight} $ für die Gesamtmenge an DATA, für die ACK nicht zurückgegeben wurde, und $ smss $ für die minimale Segmentgröße. Der Einfachheit halber werden auch Teil-ACK und Voll-ACK nicht berücksichtigt. Ausführliche Informationen zum Betrieb von NewReno finden Sie unter RFC6582. NewReno sendet DATA effizient, indem $ cwnd $ in der langsamen Startphase, in der die Wahrscheinlichkeit einer Überlastung gering ist, mit hoher Geschwindigkeit erhöht wird, während in der Phase zur Vermeidung von Überlastungen die Wahrscheinlichkeit einer Überlastung hoch ist. In haben wir eine Strategie zur Vermeidung plötzlicher Überlastungen durch schrittweise Erhöhung von $ cwnd $ verabschiedet. Bitte beachten Sie, dass die durch den ACK-Empfang ausgelöste Aktualisierungsformel ** die Aktualisierungsformel für ACK für ein Segment ** ist (ich war hier süchtig danach). Wenn beispielsweise $ cwnd = 4 $ ist, empfängt der TCP-Absender für 4 Segmente ACK [^ delayACKACK] für DATA, sodass die obige Aktualisierung ** 4-mal ** durchgeführt wird. Es gibt drei Arten von TCP-Implementierung in ns-3, aber in diesem Artikel ist ns-3 native ( Es werden nur die in src / internet / model) implementierten Algorithmen angesprochen. Mit anderen Worten, der Major CUBIC unter Linux und der Major CTCP Unter Windows. uk / ~ lewis / CTCP.pdf) ist außerhalb des Geltungsbereichs. Ich möchte diese separat vorstellen.

[^ ack]: Verzögerte Bestätigung.

4. Erstellen eines Szenarioskripts

In diesem Kapitel werden wir das darauf basierende Beispielszenario "tcp-Varianten-Vergleich.cc", seine Probleme und die modifizierte Version von "my-tcp-Varianten-Vergleich.cc" erläutern.

4.1 Basierend auf einem Beispielszenario

ns-3 ist [tcp-Varianten-Vergleich.cc](https://www.nsnam.org/docs/release/3.26/doxygen/tcp-variants-comparison_8cc] zum Vergleich von TCP-Überlastungskontrollalgorithmen. .html) Wir haben ein Beispielszenario mit dem Namen "~ / ns-3.26 / source / ns-3.26 / examples / tcp /" vorbereitet. Dieses Szenarioskript kann die Zeitänderung der folgenden Variablen verfolgen und in eine Datei ausgeben.

Im Folgenden wird der Quellcode erläutert, wobei der Schwerpunkt auf ** Trace ** liegt, dem Thema dieses Artikels.

Variablen für die Rückverfolgung

Die Zeilen 58 bis 70 definieren die für die Ablaufverfolgung verwendeten Variablen. bool first * gibt an, ob der Anfangswert des Trace-Ziels ausgegeben werden soll oder nicht, und Ptr <OutputStreamWrapper> * Stream gibt den Stream für die Ausgabe des Trace-Ziels in eine Datei an und uint32_t * Value. Stellt Variablen dar, die vorübergehend verwendet werden, wenn die zu verfolgenden Anfangswerte verarbeitet werden.

tcp-variants-comparison.cc (Zeilen 58 bis 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;

Rückruffunktion für die Ablaufverfolgung einstellen

Die Zeilen 73 bis 145 definieren die Trace-Rückruffunktion "* Tracer ()", und die Zeilen 147 bis 202 definieren die Funktion "Trace * ()", die die Rückruffunktion mit dem Trace-Ziel verknüpft. Ich werde das machen. Hier erklären wir als Beispiel "BytesInFlight", eines der Trace-Ziele.

tcp-variants-comparison.cc (Zeilen 73 bis 202)


static void
InFlightTracer (uint32_t old, uint32_t inFlight)
{
  *inFlightStream->GetStream () << Simulator::Now ().GetSeconds () << " " << inFlight << std::endl;
}

//=====Abkürzung=====

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));
}

In ns-3 werden alle Variablen "AddTraceSource ()" in der Quelldatei ("ns-3.26 / source / ns-3.26 / src / * / model /") im Szenarioskript als Ablaufverfolgungsziele festgelegt. können. Das obige "BytesInFlight" ist beispielsweise ~ / ns-3.26 / source / ns-3.26 / src / internet / model / tcp-socket-base.cc /release/3.26/doxygen/tcp-socket-base_8cc.html) hat AddTraceSource (). Jedes Mal, wenn die verfolgte Variable aktualisiert wird, ruft ns-3 die dieser Variablen zugeordnete Rückruffunktion auf. Um das Trace-Ziel festzulegen, ist es daher erforderlich, ** die Rückruffunktion zu definieren ** und ** das Trace-Ziel und die Rückruffunktion zu verknüpfen **. Als Rückruffunktion wird häufig eine Funktion wie die oben genannte InFlightTracer () verwendet. InFlightTracer () ist eine Funktion, die jedes Mal die aktuelle Zeit (Simulator :: Now (). GetSeconds ()) und den aktualisierten Wert (inFlight) ausgibt. Wenn Sie das Trace-Ziel mit der Rückruffunktion verknüpfen, können Sie die Syntax "Config :: ConnectWithoutContext (Variable, MakeCallback (& func))" verwenden, wie oben in "TraceInFlight ()" beschrieben. Hier muss "Variable" den Pfad des zu verfolgenden Objekts beschreiben. / NodeList / 1 / $ ns3 :: TcpL4Protocol / SocketList / 0 / BytesInFlight bedeutet die VariableBytesInFlight des Sockets SocketList 0, die am Knoten NodeList1 hängt. Einzelheiten zur Ablaufverfolgungsmethode für ns-3 finden Sie in Abschnitt 1.10 des Offiziellen Handbuchs.

Netzwerkkonfiguration

Stellen Sie die Netzwerkkonfiguration mit main () ab der 204. Zeile ein. Details finden Sie im Offiziellen Handbuch. Hier werden nur die Punkte beschrieben.

network.png

Die obige Abbildung zeigt ein Bild dieses Szenarios. Stellen Sie sich eine einfache Konfiguration mit einem TCP-Sender und einem Empfänger vor. Verwenden Sie BulkSendHelper, um eine große Menge an FTP-ähnlicher Datenübertragung zu simulieren. Die IP-Paketgröße beträgt 400 Byte. Die Simulationszeit beträgt standardmäßig 100 Sekunden.

Kommandozeilenargumente

Legen Sie die Befehlszeilenargumente in den Zeilen 224 bis 243 fest. Wie im vorherigen Artikel (http://qiita.com/haltaro/items/b474d924f63692c155c8) beschrieben, können Sie Befehlszeilenargumente festlegen, indem Sie "CommandLine.AddValue ()" ausführen.

tcp-variants-comparison.cc (Zeilen 224 bis 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);

In diesem Artikel werden insbesondere die folgenden Befehlszeilenargumente verwendet.

Trace-Einstellungen planen

Von der 460. bis zur 476. Zeile ist die Trace-Einstellungsfunktion (Rückruffunktion und die Funktion, die das Trace-Ziel verknüpft) wie das obige "TraceInFlight ()" geplant.

tcp-variants-comparison.cc (Zeilen 460 bis 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");
    }

In ns-3 können Sie "func (args, ...)" so planen, dass es zur "Zeit" mit der Syntax "Simulator :: Schedule (time, & func, args, ...)" ausgeführt wird. Ich bin mir jedoch nicht sicher, warum Sie im lokalen Text nicht "Trace * ()" verwenden sollten. Ich denke, es gibt wahrscheinlich ein Problem mit dem Zeitpunkt der Objekterstellung ...

4.2 Herausforderungen für tcp-Varianten-Vergleich.cc

tcp-videos-compare.cc ist ein sehr gut gemachtes Szenarioskript, mit dem Sie spielen können, indem Sie einfach die Befehlszeilenargumente anpassen. Aber ich kann die ACK- oder Überlastungsbedingungen, an denen wir interessiert sind, nicht verfolgen! Glücklicherweise sind die Variable "HighestRxAck", die die neueste ACK darstellt, und die Variable "CongState", die den Überlastungsstatus darstellt, tcp-socket-base.cc. Es ist "AddTraceSource ()" in Release / 3.26 / doxygen / tcp-socket-base_8cc.html). Daher können Sie sie mit nur wenigen Änderungen am Szenarioskript zum Ablaufverfolgungsziel hinzufügen. Im Folgenden werden wir die Methode vorstellen.

4.3 Neues Szenarioskript my-tcp-videos-compare.cc

Kopieren Sie zunächst die ursprüngliche "tcp-Varianten-Vergleich.cc" nach "~ / ns-3.26 / source / ns-3.26 / Scratch" und benennen Sie sie in "meine-TCP-Varianten-Vergleich.cc" um Machen.

$ cd ~/ns-3.26/source/ns-3.26
$ cp examples/tcp/tcp-variants-comparison.cc scratch/my-tcp-variants-comparison.cc 

Um dem Trace-Ziel den ACK- und Überlastungsstatus hinzuzufügen, fügen Sie Trace-Variablen hinzu, legen Sie Trace-Rückruffunktionen fest und planen Sie Trace-Einstellungen.

Trace-Variablen hinzufügen

Fügen Sie den Stream "ackStream" für die ACK-Ablaufverfolgung und den Stream "congStateStream" für die Ablaufverfolgung des Überlastungsstatus hinzu.

cpp:my-tcp-variants-comparison.cc(tcp-variants-comparison.Entspricht den Zeilen 58 bis 70 von 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;

Rückruffunktion für die Ablaufverfolgung einstellen

Fügen Sie die Rückruffunktion "AckTrace ()" für die ACK-Ablaufverfolgung und die Rückruffunktion "CongStateTracer ()" für die Ablaufverfolgung des Überlastungsstatus hinzu. Der Überlastungsstatus ist der Aufzählungstyp "TcpSocketState :: TcpCongState_t", der in "tcp-socket-base.h" definiert ist. Fügen Sie außerdem die Funktionen "TraceAck ()" und "TraceCongState ()" hinzu, die die obige Rückruffunktion der zu verfolgenden Variablen zuordnen.

cpp:my-tcp-variants-comparison.cc(tcp-variants-comparison.Entspricht den Zeilen 73 bis 202 von 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;
}

//=====Abkürzung=====

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));
}

Trace-Einstellungen planen

Schließlich planen Sie die oben genannten "TraceAck ()" und "TraceCongState ()".

cpp:my-tcp-variants-comparison.cc(tcp-variants-comparison.cc Entspricht den Zeilen 460 bis 476)


  if (tracing)
    {

// =====Abkürzung=====

      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!
    }

4.4 Kompilieren von my-tcp-videos-compare.cc

Sie können my-tcp-videos-compare.cc kompilieren, indem Sie. / Waf im Verzeichnis ~ / ns-3.26 / source / ns-3.26 ausführen.

$ ./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                

5. Experimentieren

5.1 Ausführen eines Szenarioskripts

Erstellen Sie zunächst das Datenspeicherverzeichnis "data".

$ mkdir ~/ns-3.26/source/ns-3.26/data

Führen Sie das folgende Shell-Skript aus, um mit allen 12 Arten von Algorithmen zu experimentieren. Wie in Vorheriger Artikel beschrieben, können Sie den Wert "value" mit "--arg = value" an das Befehlszeilenargument "arg" übergeben. Ich werde. transport_prot ist der Überlastungssteuerungsalgorithmus, prefix_name ist das Präfix des Ausgabedateinamens, tracing ist das Vorhandensein oder Fehlen von Tracing und duration ist die Simulationszeit (en).

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

5.2 Beobachten Sie die Überlastungskontrolle für alle Algorithmen

Zeichnen wir zunächst $ cwnd $ und $ ssth $ aller Algorithmen und die Änderung des Überlastungsstatus mit den folgenden "plot_cwnd_all_algorithms ()".

plottcpalgo.py


# -*- coding: utf-8 -*-
#!/usr/bin/env python


import numpy as np
import matplotlib.pyplot as plt

#Dies ist eine Funktion zur Datenformung.
def get_data(algo, variable='cwnd', duration=20.):
    file_name = 'data/Tcp' + algo + '-' + variable + '.data'
    data = np.empty((0, 2)) #Initialisieren

    #Daten aus der Datei abrufen.
    for line in open(file_name, 'r'):
        data = np.append(
            data, np.array([map(float, line[:-1].split())]),
            axis=0)
    data = data.T

    #Extrahieren Sie am Ende nur die Daten unterhalb der Dauer[duration, data[1,-1]]Zu
    #hinzufügen. Es ist ein Prozess, bis zur Dauer schön zu zeichnen.
    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 #In dieser experimentellen Konfiguration beträgt die Segmentlänge 340 Bytes.

    plt.figure(figsize=(15, 10))
    for i, algo in enumerate(algos): 
        plt.subplot(3, 4, i + 1)

        #Erfassung von cwnd-, ssth- und Überlastungsstatusdaten
        cwnd_data = get_data(algo, 'cwnd', duration) 
        ssth_data = get_data(algo, 'ssth', duration)
        state_data = get_data(algo, 'cong-state', duration)

        #Die Farben unterscheiden sich je nach Überlastungszustand.
        #OFFEN (blau), STÖRUNG (grün), WIEDERHERSTELLUNG (gelb), VERLUST (rot)
        plt.fill_between(cwnd_data[0], cwnd_data[1] / segment,
                         facecolor='lightblue') #Der Ausgangszustand ist OFFEN (blau)
        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')

        #Diagramme von cwnd (durchgezogene Linie) und ssth (gepunktete Linie).
        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) #Da der Anfangswert von ssth sehr groß ist, setzen Sie die Obergrenze mit ylim
        plt.title(algo)

    #Diagramme speichern und anzeigen
    plt.savefig('data/TcpAll' + str(duration).zfill(3) + '-cwnd.png')
    plt.show()

TcpAll20.0-cwnd.png

Die horizontale Achse ist Zeit [s] und die vertikale Achse ist $ cwnd $ und $ ssth $ [Segment]. $ cwnd $ ist eine durchgezogene Linie und $ ssth $ ist eine gepunktete Linie. Die Farben werden entsprechend dem Überlastungszustand gefärbt. $ OPEN $ ist blau, $ DISORDER $ ist grün, $ RECOVERY $ ist gelb und $ LOSS $ ist rot. Die Individualität jedes Algorithmus kam stärker heraus als ursprünglich erwartet.

5.3 Beobachten Sie die Beziehung zwischen cwnd, ACK und RTT jedes Algorithmus

Als nächstes zeichnen Sie $ cwnd $, ACK und RTT jedes Algorithmus mit dem folgenden plot_cwnd_ack_rtt_each_algorithm ().

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 #In dieser experimentellen Konfiguration beträgt die Segmentlänge 340 Bytes.
    plt.figure()

    for algo in algos:
        plt.subplot(311) #Handlung von cwnd, ssth und Überlastung

        #Erfassung von cwnd-, ssth- und Überlastungsstatusdaten
        cwnd_data = get_data(algo, 'cwnd', duration)
        ssth_data = get_data(algo, 'ssth', duration)
        state_data = get_data(algo, 'cong-state', duration)


        #Die Farben unterscheiden sich je nach Überlastungszustand.
        #OFFEN (blau), STÖRUNG (grün), WIEDERHERSTELLUNG (gelb), VERLUST (rot)
        plt.fill_between(cwnd_data[0], cwnd_data[1] / segment,
                         facecolor='lightblue') #Der Ausgangszustand ist OFFEN (blau)
        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')

        #Diagramme von cwnd (durchgezogene Linie) und ssth (gepunktete Linie).
        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) #Da der Anfangswert von ssth durcheinander ist, setzen Sie die Obergrenze mit ylim
        plt.ylabel('cwnd [segment]')
        plt.legend()
        plt.title(algo)

        plt.subplot(312) #ACK-Handlung
        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) #RTT-Plot
        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]')

        #Bild speichern.
        plt.savefig('data/Tcp' + algo + 'Sub-' + str(int(duration)).zfill(3) +
                    '-cwnd-ack-rtt.png')
        plt.clf()
    plt.show()

Im Folgenden werden wir die Ergebnisse am Beispiel von NewReno analysieren. Zu Ihrer Information sind auch die Ergebnisse anderer Algorithmen enthalten.

NewReno

TcpNewReno020-cwnd-ack-rtt.png

Um 1,93 [s] werden drei doppelte ACKs empfangen und der Status wechselt in den Status $ RECOVERY $. Ungefährer Durchsatz zu diesem Zeitpunkt:

\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]}

Hier betrug die Bandbreite der Engpassverbindung 2,0 Mbit / s (siehe Abschnitt 4.1), sodass es nicht unnatürlich ist, wenn eine Überlastung auftritt [^ Analyse]. Nach dem Übergang zu $ RECOVERY $ können Sie feststellen, dass die ACK- und RTT-Updates gestoppt wurden. Sie können auch sehen, dass die Aktualisierungen für $ cwnd $ und $ ssth $ mit Abschnitt 3.3 übereinstimmen. Gegen 3.26 [s] tritt eine Zeitüberschreitung auf, ohne dass eine neue ACK empfangen wird, und es wird in den Status $ LOSS $ übergegangen. Sie können sehen, dass die Aktualisierungen von $ cwnd $ und $ ssth $ mit Abschnitt 3.3 übereinstimmen. Gegen 4.69 Uhr wird endlich eine neue ACK empfangen und der Status wechselt in den Status $ OPEN $.

[^ Analyse]: Vielleicht. Ich denke, eine detailliertere Analyse wie die Warteschlangenanalyse ist erforderlich, aber ich bin erschöpft ...

Andere Algorithmen

Zu Ihrer Information werden auch die Ergebnisse anderer Algorithmen veröffentlicht.

TcpHighSpeed020-cwnd-ack-rtt.png

TcpHybla020-cwnd-ack-rtt.png

TcpWestwood020-cwnd-ack-rtt.png

TcpWestwoodPlus020-cwnd-ack-rtt.png

TcpVegas020-cwnd-ack-rtt.png

TcpScalable020-cwnd-ack-rtt.png

TcpVeno020-cwnd-ack-rtt.png

TcpBic020-cwnd-ack-rtt.png

TcpYeah020-cwnd-ack-rtt.png

TcpIllinois020-cwnd-ack-rtt.png

TcpHtcp020-cwnd-ack-rtt.png

6. Fazit

In diesem Artikel habe ich ns-3 verwendet, um die TCP-Überlastungskontrolle zu simulieren und sie mit Python zu visualisieren. Als Anfänger konnte ich ein Gefühl für TCP bekommen. Wir haben auch die Exzellenz des ns-3-Beispielszenarios bestätigt. Von nun an CUBIC und CTCP Ich möchte die Implementierung wichtiger Algorithmen wie) und der neuesten Algorithmen wie Remy in Frage stellen. Alternativ halte ich es für gut, die Konkurrenz zwischen verschiedenen Algorithmen zu beobachten. Vielen Dank für das Lesen bis zum Ende!

Referenz

Bei der Erstellung dieses Artikels habe ich auf Folgendes verwiesen. Vielen Dank!

Recommended Posts

Beobachten Sie die TCP-Überlastungskontrolle mit ns-3
Kontrollieren Sie Skripte mit Ausnahmen
Steuern Sie mehrere Roboter mit jupyter-lab