diff --git a/doc/tutorial/tracing.texi b/doc/tutorial/tracing.texi index 869e561bb..5b91d96a7 100644 --- a/doc/tutorial/tracing.texi +++ b/doc/tutorial/tracing.texi @@ -17,6 +17,8 @@ @menu * Background:: * Overview:: +* A Real Example:: +* Using Mid-Level Helpers:: @end menu @c ============================================================================ @@ -1901,4 +1903,30 @@ file ``cwnd.png'' in all of its glory, that looks like: @sp 1 @center @image{figures/cwnd,,,,png} +@c ============================================================================ +@c Using Mid-Level Helpers +@c ============================================================================ +@node Using Mid-Level Helpers +@section Using Mid-Level Helpers + +In the previous section, we showed how to hook a trace source and get hopefully +interesting information out of a simulation. Perhaps you will recall that we +called logging to the standard output using @code{std::cout} a ``Blunt Instrument'' +much earlier in this chapter. We also wrote about how it was a problem having +to parse the log output in order to isolate interesting information. It may +have occurred to you that we just spent a lot of time implementing an example +that exhibits all of the problems we purport to fix with the @code{ns-3} tracing +system! You would be correct. But, bear with us. We're not done yet. + +One of the most important things we want to do is to is to have the ability to +easily control the amount of output coming out of the simulation; and we also +want to save those data to a file so we can refer back to it later. We can use +the mid-level trace helpers provided in @code{ns-3} to do just that and complete +the picture. + + + + + + diff --git a/examples/tutorial/sixth.cc b/examples/tutorial/sixth.cc new file mode 100644 index 000000000..4d944a97e --- /dev/null +++ b/examples/tutorial/sixth.cc @@ -0,0 +1,231 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "ns3/core-module.h" +#include "ns3/common-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/ascii-trace-helper.h" +#include "ns3/pcap-helper.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("SixthScriptExample"); + +// =========================================================================== +// +// node 0 node 1 +// +----------------+ +----------------+ +// | ns-3 TCP | | ns-3 TCP | +// +----------------+ +----------------+ +// | 10.1.1.1 | | 10.1.1.2 | +// +----------------+ +----------------+ +// | point-to-point | | point-to-point | +// +----------------+ +----------------+ +// | | +// +---------------------+ +// 5 Mbps, 2 ms +// +// +// We want to look at changes in the ns-3 TCP congestion window. We need +// to crank up a flow and hook the CongestionWindow attribute on the socket +// of the sender. Normally one would use an on-off application to generate a +// flow, but this has a couple of problems. First, the socket of the on-off +// application is not created until Application Start time, so we wouldn't be +// able to hook the socket (now) at configuration time. Second, even if we +// could arrange a call after start time, the socket is not public so we +// couldn't get at it. +// +// So, we can cook up a simple version of the on-off application that does what +// we want. On the plus side we don't need all of the complexity of the on-off +// application. On the minus side, we don't have a helper, so we have to get +// a little more involved in the details, but this is trivial. +// +// So first, we create a socket and do the trace connect on it; then we pass +// this socket into the constructor of our simple application which we then +// install in the source node. +// =========================================================================== +// +class MyApp : public Application +{ +public: + + MyApp (); + virtual ~MyApp(); + + void Setup (Ptr socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate); + +private: + virtual void StartApplication (void); + virtual void StopApplication (void); + + void ScheduleTx (void); + void SendPacket (void); + + 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; +}; + +MyApp::MyApp () + : m_socket (0), + m_peer (), + m_packetSize (0), + m_nPackets (0), + m_dataRate (0), + m_sendEvent (), + m_running (false), + m_packetsSent (0) +{ +} + +MyApp::~MyApp() +{ + m_socket = 0; +} + +void +MyApp::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; +} + +void +MyApp::StartApplication (void) +{ + m_running = true; + m_packetsSent = 0; + m_socket->Bind (); + m_socket->Connect (m_peer); + SendPacket (); +} + +void +MyApp::StopApplication (void) +{ + m_running = false; + + if (m_sendEvent.IsRunning ()) + { + Simulator::Cancel (m_sendEvent); + } + + if (m_socket) + { + m_socket->Close (); + } +} + +void +MyApp::SendPacket (void) +{ + Ptr packet = Create (m_packetSize); + m_socket->Send (packet); + + if (++m_packetsSent < m_nPackets) + { + ScheduleTx (); + } +} + +void +MyApp::ScheduleTx (void) +{ + if (m_running) + { + Time tNext (Seconds (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ()))); + m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this); + } +} + +static void +CwndChange (Ptr stream, uint32_t oldCwnd, uint32_t newCwnd) +{ + *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl; +} + +static void +RxDrop (Ptr file, Ptr p) +{ + file->Write(Simulator::Now(), p); +} + +int +main (int argc, char *argv[]) +{ + NodeContainer nodes; + nodes.Create (2); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + + Ptr em = CreateObjectWithAttributes ( + "RanVar", RandomVariableValue (UniformVariable (0., 1.)), + "ErrorRate", DoubleValue (0.00001)); + devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em)); + + InternetStackHelper stack; + stack.Install (nodes); + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.252"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + 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.)); + + Ptr ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ()); + + AsciiTraceHelper asciiTraceHelper; + Ptr stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd"); + ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream)); + + Ptr app = CreateObject (); + app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps")); + nodes.Get (0)->AddApplication (app); + app->SetStartTime (Seconds (1.)); + app->SetStopTime (Seconds (20.)); + + PcapHelper pcapHelper; + Ptr file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_EN10MB); + devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file)); + + Simulator::Stop (Seconds(20)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} + diff --git a/examples/tutorial/wscript b/examples/tutorial/wscript index 1c340ab6d..6f9df8163 100644 --- a/examples/tutorial/wscript +++ b/examples/tutorial/wscript @@ -18,3 +18,6 @@ def build(bld): obj = bld.create_ns3_program('fifth', ['core', 'simulator', 'point-to-point', 'internet-stack']) obj.source = 'fifth.cc' + + obj = bld.create_ns3_program('sixth', ['core', 'simulator', 'point-to-point', 'internet-stack']) + obj.source = 'sixth.cc'