From 4845e2cbcd7f1dbcaaf156423d934e8088403b2a Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 5 Feb 2023 10:09:51 -0800 Subject: [PATCH] doc: Remove outdated tutorial reference to MyApp --- doc/tutorial/source/tracing.rst | 289 +++++++++++++++++++------------- 1 file changed, 171 insertions(+), 118 deletions(-) diff --git a/doc/tutorial/source/tracing.rst b/doc/tutorial/source/tracing.rst index 2bcaf89b7..12a20dcf1 100644 --- a/doc/tutorial/source/tracing.rst +++ b/doc/tutorial/source/tracing.rst @@ -1379,7 +1379,7 @@ The two solutions to this conundrum are give the object to the system to use during simulation time. We took the second approach in the ``fifth.cc`` example. This -decision required us to create the ``MyApp`` ``Application``, the +decision required us to create the ``TutorialApp`` ``Application``, the entire purpose of which is to take a ``Socket`` as a parameter. Walkthrough: ``fifth.cc`` @@ -1406,18 +1406,21 @@ see some familiar looking code:: * Foundation, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include - #include "ns3/core-module.h" - #include "ns3/network-module.h" - #include "ns3/internet-module.h" - #include "ns3/point-to-point-module.h" + #include "tutorial-app.h" + #include "ns3/applications-module.h" + #include "ns3/core-module.h" + #include "ns3/internet-module.h" + #include "ns3/network-module.h" + #include "ns3/point-to-point-module.h" + + #include using namespace ns3; NS_LOG_COMPONENT_DEFINE("FifthScriptExample"); -This has all been covered, so we won't rehash it. The next lines of +The next lines of source are the network illustration and a comment addressing the problem described above with ``Socket``. @@ -1460,44 +1463,67 @@ problem described above with ``Socket``. This should also be self-explanatory. -The next part is the declaration of the ``MyApp`` ``Application`` that -we put together to allow the ``Socket`` to be created at configuration -time. +Previous versions of |ns3| declared a custom application called ``MyApp`` +for use in this program. Current versions of |ns3| have moved this to +a separate header file (``tutorial-app.h'') and implementation file +(``tutorial-app.cc''). This simple application allows the ``Socket'' +to be created at configuration time. :: - class MyApp : public Application + /** + * Tutorial - a simple Application sending packets. + */ + class TutorialApp : public Application { - public: + public: + TutorialApp(); + ~TutorialApp() override; - MyApp(); - virtual ~MyApp(); + /** + * Register this type. + * \return The TypeId. + */ + static TypeId GetTypeId(); - void Setup(Ptr socket, Address address, uint32_t packetSize, - uint32_t nPackets, DataRate dataRate); + /** + * Setup the socket. + * \param socket The socket. + * \param address The destination address. + * \param packetSize The packet size to transmit. + * \param nPackets The number of packets to transmit. + * \param dataRate the data rate to use. + */ + void Setup(Ptr socket, + Address address, + uint32_t packetSize, + uint32_t nPackets, + DataRate dataRate); - private: - virtual void StartApplication(); - virtual void StopApplication(); + private: + void StartApplication() override; + void StopApplication() override; - void ScheduleTx(); - void SendPacket(); + /// Schedule a new transmission. + void ScheduleTx(); + /// Send a packet. + void SendPacket(); - Ptr m_socket; - Address m_peer; - uint32_t m_packetSize; - uint32_t m_nPackets; - DataRate m_dataRate; - EventId m_sendEvent; - bool m_running; - uint32_t m_packetsSent; + Ptr m_socket; //!< The transmission socket. + Address m_peer; //!< The destination address. + uint32_t m_packetSize; //!< The packet size. + uint32_t m_nPackets; //!< The number of packets to send. + DataRate m_dataRate; //!< The data rate to use. + EventId m_sendEvent; //!< Send event. + bool m_running; //!< True if the application is running. + uint32_t m_packetsSent; //!< The number of packets sent. }; You can see that this class inherits from the |ns3| ``Application`` class. Take a look at ``src/network/model/application.h`` if you are -interested in what is inherited. The ``MyApp`` class is obligated to +interested in what is inherited. The ``TutorialApp`` class is obligated to override the ``StartApplication`` and ``StopApplication`` methods. -These methods are automatically called when ``MyApp`` is required to +These methods are automatically called when ``TutorialApp`` is required to start and stop sending data during the simulation. Starting/Stopping Applications @@ -1537,13 +1563,13 @@ as a result of the ``apps.Stop`` call. The ultimate result of these calls is that we want to have the simulator automatically make calls into our ``Applications`` to tell -them when to start and stop. In the case of ``MyApp``, it inherits +them when to start and stop. In the case of ``TutorialApp``, it inherits from class ``Application`` and overrides ``StartApplication``, and ``StopApplication``. These are the functions that will be called by -the simulator at the appropriate time. In the case of ``MyApp`` you -will find that ``MyApp::StartApplication`` does the initial ``Bind``, +the simulator at the appropriate time. In the case of ``TutorialApp`` you +will find that ``TutorialApp::StartApplication`` does the initial ``Bind``, and ``Connect`` on the socket, and then starts data flowing by calling -``MyApp::SendPacket``. ``MyApp::StopApplication`` stops generating +``TutorialApp::SendPacket``. ``TutorialApp::StopApplication`` stops generating packets by cancelling any pending send events then closes the socket. One of the nice things about |ns3| is that you can completely ignore @@ -1618,6 +1644,7 @@ look at ``src/network/model/application.cc`` and you will find:: void Application::DoInitialize() { + NS_LOG_FUNCTION(this); m_startEvent = Simulator::Schedule(m_startTime, &Application::StartApplication, this); if (m_stopTime != TimeStep(0)) { @@ -1652,27 +1679,27 @@ flow of data from the ``Application`` This has been another fairly long journey, but it only has to be made once, and you now understand another very deep piece of |ns3|. -The MyApp Application -~~~~~~~~~~~~~~~~~~~~~ +The TutorialApp Application +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``MyApp`` ``Application`` needs a constructor and a destructor, of +The ``TutorialApp`` ``Application`` needs a constructor and a destructor, of course:: - MyApp::MyApp() - : m_socket(0), - m_peer(), - m_packetSize(0), - m_nPackets(0), - m_dataRate(0), - m_sendEvent(), - m_running(false), - m_packetsSent(0) + TutorialApp::TutorialApp() + : m_socket(nullptr), + m_peer(), + m_packetSize(0), + m_nPackets(0), + m_dataRate(0), + m_sendEvent(), + m_running(false), + m_packetsSent(0) { } - MyApp::~MyApp() + TutorialApp::~TutorialApp() { - m_socket = 0; + m_socket = nullptr; } The existence of the next bit of code is the whole reason why we wrote @@ -1681,14 +1708,17 @@ this ``Application`` in the first place. :: void - MyApp::Setup(Ptr socket, Address address, uint32_t packetSize, - uint32_t nPackets, DataRate dataRate) + TutorialApp::Setup(Ptr socket, + Address address, + uint32_t packetSize, + uint32_t nPackets, + DataRate dataRate) { - m_socket = socket; - m_peer = address; - m_packetSize = packetSize; - m_nPackets = nPackets; - m_dataRate = dataRate; + m_socket = socket; + m_peer = address; + m_packetSize = packetSize; + m_nPackets = nPackets; + m_dataRate = dataRate; } This code should be pretty self-explanatory. We are just initializing @@ -1702,13 +1732,13 @@ passing it to the ``Setup`` method. :: void - MyApp::StartApplication() + TutorialApp::StartApplication() { - m_running = true; - m_packetsSent = 0; - m_socket->Bind(); - m_socket->Connect(m_peer); - SendPacket(); + m_running = true; + m_packetsSent = 0; + m_socket->Bind(); + m_socket->Connect(m_peer); + SendPacket(); } The above code is the overridden implementation @@ -1731,18 +1761,18 @@ creating simulation events. :: void - MyApp::StopApplication() + TutorialApp::StopApplication() { - m_running = false; + m_running = false; - if (m_sendEvent.IsRunning()) + if (m_sendEvent.IsRunning()) { - Simulator::Cancel(m_sendEvent); + Simulator::Cancel(m_sendEvent); } - if (m_socket) + if (m_socket) { - m_socket->Close(); + m_socket->Close(); } } @@ -1765,14 +1795,14 @@ chain of events that describes the ``Application`` behavior. :: void - MyApp::SendPacket() + TutorialApp::SendPacket() { - Ptr packet = Create(m_packetSize); - m_socket->Send(packet); + Ptr packet = Create(m_packetSize); + m_socket->Send(packet); - if (++m_packetsSent < m_nPackets) + if (++m_packetsSent < m_nPackets) { - ScheduleTx(); + ScheduleTx(); } } @@ -1788,12 +1818,12 @@ decides it has sent enough. :: void - MyApp::ScheduleTx() + TutorialApp::ScheduleTx() { - if (m_running) + if (m_running) { - Time tNext(Seconds(m_packetSize * 8 / static_cast(m_dataRate.GetBitRate()))); - m_sendEvent = Simulator::Schedule(tNext, &MyApp::SendPacket, this); + Time tNext(Seconds(m_packetSize * 8 / static_cast(m_dataRate.GetBitRate()))); + m_sendEvent = Simulator::Schedule(tNext, &TutorialApp::SendPacket, this); } } @@ -1819,7 +1849,7 @@ code implements the corresponding trace sink:: static void CwndChange(uint32_t oldCwnd, uint32_t newCwnd) { - NS_LOG_UNCOND(Simulator::Now().GetSeconds() << "\t" << newCwnd); + NS_LOG_UNCOND(Simulator::Now().GetSeconds() << "\t" << newCwnd); } This should be very familiar to you now, so we won't dwell on the @@ -1838,7 +1868,7 @@ demonstrate this working. static void RxDrop(Ptr p) { - NS_LOG_UNCOND("RxDrop at " << Simulator::Now().GetSeconds()); + NS_LOG_UNCOND("RxDrop at " << Simulator::Now().GetSeconds()); } This trace sink will be connected to the "PhyRxDrop" trace source of @@ -1858,20 +1888,45 @@ single parameter which is a ``Ptr`` (assuming we use Main Program ~~~~~~~~~~~~ -The following code should be very familiar to you by now:: +The main function starts off by configuring the TCP type to use a legacy +``NewReno`` congestion control variant, with what is called the ``classic'' +TCP loss recovery mechanism. When this tutorial program was originally +written, these were the default TCP configurations, but over time, +|ns3| TCP has evolved to use the current Linux TCP defaults of ``Cubic`` +and ``Prr'' loss recovery. The first statements also configure the +command-line argument processing. + +:: int - main(int argc, char *argv[]) + main(int argc, char* argv[]) { - NodeContainer nodes; - nodes.Create(2); + CommandLine cmd(__FILE__); + cmd.Parse(argc, argv); - PointToPointHelper pointToPoint; - pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps")); - pointToPoint.SetChannelAttribute("Delay", StringValue("2ms")); + // In the following three lines, TCP NewReno is used as the congestion + // control algorithm, the initial congestion window of a TCP connection is + // set to 1 packet, and the classic fast recovery algorithm is used. Note + // that this configuration is used only to demonstrate how TCP parameters + // can be configured in ns-3. Otherwise, it is recommended to use the default + // settings of TCP in ns-3. + Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::TcpNewReno")); + Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(1)); + Config::SetDefault("ns3::TcpL4Protocol::RecoveryType", + TypeIdValue(TypeId::LookupByName("ns3::TcpClassicRecovery"))); - NetDeviceContainer devices; - devices = pointToPoint.Install(nodes); + +The following code should be very familiar to you by now:: + + NodeContainer nodes; + nodes.Create(2); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps")); + pointToPoint.SetChannelAttribute("Delay", StringValue("2ms")); + + NetDeviceContainer devices; + devices = pointToPoint.Install(nodes); This creates two nodes with a point-to-point channel between them, just as shown in the illustration at the start of the file. @@ -1890,9 +1945,9 @@ into a ``Channel`` at a given *rate*. :: - Ptr em = CreateObject(); - em->SetAttribute("ErrorRate", DoubleValue(0.00001)); - devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(em)); + Ptr em = CreateObject(); + em->SetAttribute("ErrorRate", DoubleValue(0.00001)); + devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(em)); The above code instantiates a ``RateErrorModel`` Object, and we set the "ErrorRate" ``Attribute`` to the desired value. We then set the @@ -1902,12 +1957,12 @@ retransmissions and make our plot a little more interesting. :: - InternetStackHelper stack; - stack.Install(nodes); + InternetStackHelper stack; + stack.Install(nodes); - Ipv4AddressHelper address; - address.SetBase("10.1.1.0", "255.255.255.252"); - Ipv4InterfaceContainer interfaces = address.Assign(devices); + Ipv4AddressHelper address; + address.SetBase("10.1.1.0", "255.255.255.252"); + Ipv4InterfaceContainer interfaces = address.Assign(devices); The above code should be familiar. It installs internet stacks on our two nodes and creates interfaces and assigns IP addresses for the @@ -1919,20 +1974,20 @@ is commonly used in |ns3| for that purpose. :: - uint16_t sinkPort = 8080; - Address sinkAddress(InetSocketAddress(interfaces.GetAddress(1), sinkPort)); - PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", - InetSocketAddress(Ipv4Address::GetAny(), sinkPort)); - ApplicationContainer sinkApps = packetSinkHelper.Install(nodes.Get(1)); - sinkApps.Start(Seconds(0.)); - sinkApps.Stop(Seconds(20.)); + uint16_t sinkPort = 8080; + Address sinkAddress(InetSocketAddress(interfaces.GetAddress(1), sinkPort)); + PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", + InetSocketAddress(Ipv4Address::GetAny(), sinkPort)); + ApplicationContainer sinkApps = packetSinkHelper.Install(nodes.Get(1)); + sinkApps.Start(Seconds(0.)); + sinkApps.Stop(Seconds(20.)); This should all be familiar, with the exception of, :: - PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", - InetSocketAddress(Ipv4Address::GetAny(), sinkPort)); + PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", + InetSocketAddress(Ipv4Address::GetAny(), sinkPort)); This code instantiates a ``PacketSinkHelper`` and tells it to create sockets using the class ``ns3::TcpSocketFactory``. This class @@ -1952,10 +2007,8 @@ trace source. :: - Ptr ns3TcpSocket = Socket::CreateSocket(nodes.Get(0), - TcpSocketFactory::GetTypeId()); - ns3TcpSocket->TraceConnectWithoutContext("CongestionWindow", - MakeCallback(&CwndChange)); + Ptr ns3TcpSocket = Socket::CreateSocket(nodes.Get(0), TcpSocketFactory::GetTypeId()); + ns3TcpSocket->TraceConnectWithoutContext("CongestionWindow", MakeCallback(&CwndChange)); The first statement calls the static member function ``Socket::CreateSocket`` and provides a Node and an explicit @@ -1975,19 +2028,19 @@ didn't go to any trouble to create a helper to manage the ``Application`` so we are going to have to create and install it "manually". This is actually quite easy:: - Ptr app = CreateObject(); - app->Setup(ns3TcpSocket, sinkAddress, 1040, 1000, DataRate("1Mbps")); - nodes.Get(0)->AddApplication(app); - app->Start(Seconds(1.)); - app->Stop(Seconds(20.)); + Ptr app = CreateObject(); + app->Setup(ns3TcpSocket, sinkAddress, 1040, 1000, DataRate("1Mbps")); + nodes.Get(0)->AddApplication(app); + app->Start(Seconds(1.)); + app->Stop(Seconds(20.)); -The first line creates an ``Object`` of type ``MyApp`` -- our +The first line creates an ``Object`` of type ``TutorialApp`` -- our ``Application``. The second line tells the ``Application`` what ``Socket`` to use, what address to connect to, how much data to send at each send event, how many send events to generate and the rate at which to produce data from those events. -Next, we manually add the ``MyApp Application`` to the source Node and +Next, we manually add the ``TutorialApp Application`` to the source Node and explicitly call the ``Start`` and ``Stop`` methods on the ``Application`` to tell it when to start and stop doing its thing. @@ -1996,7 +2049,7 @@ We need to actually do the connect from the receiver point-to-point :: - devices.Get(1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback(&RxDrop)); + devices.Get(1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback(&RxDrop)); It should now be obvious that we are getting a reference to the receiving ``Node NetDevice`` from its container and connecting the @@ -2029,7 +2082,7 @@ Running ``fifth.cc`` ++++++++++++++++++++ Since we have provided the file ``fifth.cc`` for you, if you have -built your distribution (in debug mode since it uses ``NS_LOG`` -- recall +built your distribution (in debug or default mode since it uses ``NS_LOG`` -- recall that optimized builds optimize out ``NS_LOG``) it will be waiting for you to run.